job_ops-mcp 0.3.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.
- package/.env.example +33 -0
- package/LICENSE +21 -0
- package/README.md +400 -0
- package/config/profile.example.yml +67 -0
- package/cv.example.md +53 -0
- package/dist/cli.js +385 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js +63 -0
- package/dist/config.js.map +1 -0
- package/dist/core/browser.js +27 -0
- package/dist/core/browser.js.map +1 -0
- package/dist/core/content_hash.js +11 -0
- package/dist/core/content_hash.js.map +1 -0
- package/dist/core/csv.js +107 -0
- package/dist/core/csv.js.map +1 -0
- package/dist/core/cv_parse.js +201 -0
- package/dist/core/cv_parse.js.map +1 -0
- package/dist/core/html.js +10 -0
- package/dist/core/html.js.map +1 -0
- package/dist/core/jd_normalize.js +99 -0
- package/dist/core/jd_normalize.js.map +1 -0
- package/dist/core/jobs.js +106 -0
- package/dist/core/jobs.js.map +1 -0
- package/dist/core/llm.js +227 -0
- package/dist/core/llm.js.map +1 -0
- package/dist/core/modes.js +55 -0
- package/dist/core/modes.js.map +1 -0
- package/dist/core/outreach_safety.js +77 -0
- package/dist/core/outreach_safety.js.map +1 -0
- package/dist/core/profile.js +88 -0
- package/dist/core/profile.js.map +1 -0
- package/dist/core/providers/amazon.js +36 -0
- package/dist/core/providers/amazon.js.map +1 -0
- package/dist/core/providers/ashby.js +31 -0
- package/dist/core/providers/ashby.js.map +1 -0
- package/dist/core/providers/google.js +46 -0
- package/dist/core/providers/google.js.map +1 -0
- package/dist/core/providers/greenhouse.js +55 -0
- package/dist/core/providers/greenhouse.js.map +1 -0
- package/dist/core/providers/http.js +36 -0
- package/dist/core/providers/http.js.map +1 -0
- package/dist/core/providers/index.js +53 -0
- package/dist/core/providers/index.js.map +1 -0
- package/dist/core/providers/lever.js +32 -0
- package/dist/core/providers/lever.js.map +1 -0
- package/dist/core/providers/playwright_generic.js +53 -0
- package/dist/core/providers/playwright_generic.js.map +1 -0
- package/dist/core/providers/types.js +2 -0
- package/dist/core/providers/types.js.map +1 -0
- package/dist/core/providers/workday.js +44 -0
- package/dist/core/providers/workday.js.map +1 -0
- package/dist/core/render.js +253 -0
- package/dist/core/render.js.map +1 -0
- package/dist/core/reports.js +257 -0
- package/dist/core/reports.js.map +1 -0
- package/dist/core/resources.js +40 -0
- package/dist/core/resources.js.map +1 -0
- package/dist/core/scan_engine.js +164 -0
- package/dist/core/scan_engine.js.map +1 -0
- package/dist/core/scheduler.js +117 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/db.js +60 -0
- package/dist/db.js.map +1 -0
- package/dist/http/app.js +35 -0
- package/dist/http/app.js.map +1 -0
- package/dist/http/dashboard.js +131 -0
- package/dist/http/dashboard.js.map +1 -0
- package/dist/mcp/define.js +35 -0
- package/dist/mcp/define.js.map +1 -0
- package/dist/mcp/server.js +103 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/apply_prefill.js +167 -0
- package/dist/mcp/tools/apply_prefill.js.map +1 -0
- package/dist/mcp/tools/batch_evaluate.js +143 -0
- package/dist/mcp/tools/batch_evaluate.js.map +1 -0
- package/dist/mcp/tools/evaluate_job.js +181 -0
- package/dist/mcp/tools/evaluate_job.js.map +1 -0
- package/dist/mcp/tools/generate_materials.js +126 -0
- package/dist/mcp/tools/generate_materials.js.map +1 -0
- package/dist/mcp/tools/get_report.js +24 -0
- package/dist/mcp/tools/get_report.js.map +1 -0
- package/dist/mcp/tools/ops.js +321 -0
- package/dist/mcp/tools/ops.js.map +1 -0
- package/dist/mcp/tools/outreach.js +481 -0
- package/dist/mcp/tools/outreach.js.map +1 -0
- package/dist/mcp/tools/render_pdf.js +27 -0
- package/dist/mcp/tools/render_pdf.js.map +1 -0
- package/dist/mcp/tools/scan_portals.js +35 -0
- package/dist/mcp/tools/scan_portals.js.map +1 -0
- package/dist/mcp/tools/scheduler.js +32 -0
- package/dist/mcp/tools/scheduler.js.map +1 -0
- package/dist/mcp/tools/stories.js +172 -0
- package/dist/mcp/tools/stories.js.map +1 -0
- package/dist/mcp/tools/tracker.js +183 -0
- package/dist/mcp/tools/tracker.js.map +1 -0
- package/dist/mcp/tools/visa.js +219 -0
- package/dist/mcp/tools/visa.js.map +1 -0
- package/dist/migrations/001_initial.sql +505 -0
- package/dist/migrations/002_llm_and_digest.sql +42 -0
- package/dist/server.js +55 -0
- package/dist/server.js.map +1 -0
- package/fonts/dm-sans-latin-ext.woff2 +0 -0
- package/fonts/dm-sans-latin.woff2 +0 -0
- package/fonts/space-grotesk-latin-ext.woff2 +0 -0
- package/fonts/space-grotesk-latin.woff2 +0 -0
- package/modes/career_packet.md +91 -0
- package/modes/negotiation_playbook.md +64 -0
- package/modes/outreach_tone.md +80 -0
- package/modes/report_format.md +83 -0
- package/modes/rubric.md +119 -0
- package/modes/tailoring_rules.md +102 -0
- package/package.json +67 -0
- package/portals.example.yml +95 -0
- package/templates/cover-template.html +64 -0
- package/templates/cv-template.html +421 -0
- package/templates/cv-template.tex +123 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
// G7 — profile + ops tools.
|
|
2
|
+
// evaluate_training, evaluate_project, deep_research, daily_digest,
|
|
3
|
+
// get_career_packet, update_career_packet, enrich_company, cost_estimate
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { randomUUID, createHash } from 'node:crypto';
|
|
6
|
+
import { config } from '../../config.js';
|
|
7
|
+
import { getDb, runInWriteLock } from '../../db.js';
|
|
8
|
+
import { defineTool, okResult, errResult } from '../define.js';
|
|
9
|
+
import { chatLogged, llmAvailable, COST_TABLE, estimateCostUsd } from '../../core/llm.js';
|
|
10
|
+
import { getActiveCareerPacket } from '../../core/profile.js';
|
|
11
|
+
import { getMode } from '../../core/modes.js';
|
|
12
|
+
import { findCompanyByName } from '../../core/jobs.js';
|
|
13
|
+
// ── evaluate_training ────────────────────────────────────────────────────────
|
|
14
|
+
export const evaluateTrainingTool = defineTool({
|
|
15
|
+
name: 'evaluate_training',
|
|
16
|
+
title: 'Score a course / cert against the profile',
|
|
17
|
+
description: 'Scores a training input (URL, syllabus, or pasted text) against the candidate profile. ' +
|
|
18
|
+
'chat-mode default returns the rubric + packet for the chat to score. api-mode runs the LLM.',
|
|
19
|
+
inputSchema: {
|
|
20
|
+
input: z.string().min(1).describe('URL, syllabus text, or paste of training description.'),
|
|
21
|
+
mode: z.enum(['chat', 'api']).default('chat'),
|
|
22
|
+
},
|
|
23
|
+
handler: async (args) => {
|
|
24
|
+
const packet = getActiveCareerPacket()?.content ?? '';
|
|
25
|
+
const rubric = getMode('rubric.md');
|
|
26
|
+
if (args.mode === 'chat') {
|
|
27
|
+
return okResult({
|
|
28
|
+
instructions: 'Score this training on (a) skill_gap_fill 0-100 against the rubric profile, (b) market_signal 0-100 ' +
|
|
29
|
+
'(how much hiring managers value the cert in the target roles), (c) time_to_value (weeks). ' +
|
|
30
|
+
'Output STRICT JSON: { skill_gap_fill, market_signal, time_to_value_weeks, recommendation: "do_now"|"backlog"|"skip", reasoning }.',
|
|
31
|
+
training_input: args.input,
|
|
32
|
+
rubric, career_packet: packet,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
if (!llmAvailable())
|
|
36
|
+
return errResult('No LLM configured for api mode.');
|
|
37
|
+
const system = rubric + '\n\n== CAREER PACKET ==\n' + packet +
|
|
38
|
+
'\n\nReturn STRICT JSON: { skill_gap_fill, market_signal, time_to_value_weeks, recommendation, reasoning }.';
|
|
39
|
+
const call = await chatLogged('evaluate_training.api', [
|
|
40
|
+
{ role: 'system', content: system }, { role: 'user', content: args.input },
|
|
41
|
+
], { responseFormat: 'json_object', temperature: 0.3 });
|
|
42
|
+
if (!call.parseOk)
|
|
43
|
+
return errResult(`parse error: ${call.parseError}`);
|
|
44
|
+
return okResult(call.parsed);
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
// ── evaluate_project ─────────────────────────────────────────────────────────
|
|
48
|
+
export const evaluateProjectTool = defineTool({
|
|
49
|
+
name: 'evaluate_project',
|
|
50
|
+
title: 'Score a portfolio-project idea',
|
|
51
|
+
description: 'Scores a portfolio-project idea against target roles for resume signal + interview leverage. ' +
|
|
52
|
+
'chat-mode default returns the context; api-mode runs the LLM.',
|
|
53
|
+
inputSchema: {
|
|
54
|
+
input: z.string().min(1),
|
|
55
|
+
mode: z.enum(['chat', 'api']).default('chat'),
|
|
56
|
+
},
|
|
57
|
+
handler: async (args) => {
|
|
58
|
+
const packet = getActiveCareerPacket()?.content ?? '';
|
|
59
|
+
const rubric = getMode('rubric.md');
|
|
60
|
+
if (args.mode === 'chat') {
|
|
61
|
+
return okResult({
|
|
62
|
+
instructions: 'Score this project idea on (a) resume_signal 0-100, (b) interview_story_value 0-100, ' +
|
|
63
|
+
'(c) effort_weeks, (d) shipping_risk 0-100. Recommend ship_now / refine / skip. ' +
|
|
64
|
+
'Output STRICT JSON.',
|
|
65
|
+
project_input: args.input,
|
|
66
|
+
rubric, career_packet: packet,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
if (!llmAvailable())
|
|
70
|
+
return errResult('No LLM configured for api mode.');
|
|
71
|
+
const system = rubric + '\n\n== CAREER PACKET ==\n' + packet +
|
|
72
|
+
'\n\nReturn STRICT JSON: { resume_signal, interview_story_value, effort_weeks, shipping_risk, recommendation, reasoning }.';
|
|
73
|
+
const call = await chatLogged('evaluate_project.api', [
|
|
74
|
+
{ role: 'system', content: system }, { role: 'user', content: args.input },
|
|
75
|
+
], { responseFormat: 'json_object', temperature: 0.3 });
|
|
76
|
+
if (!call.parseOk)
|
|
77
|
+
return errResult(`parse error: ${call.parseError}`);
|
|
78
|
+
return okResult(call.parsed);
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
// ── deep_research ────────────────────────────────────────────────────────────
|
|
82
|
+
//
|
|
83
|
+
// Combined company brief: cached enrichment rows (comp / culture / recent_news) + a
|
|
84
|
+
// structured suggestion of what to research next. chat-mode default returns context;
|
|
85
|
+
// api-mode summarises whatever's in `notes` or pulls from a chat-provided web snapshot.
|
|
86
|
+
export const deepResearchTool = defineTool({
|
|
87
|
+
name: 'deep_research',
|
|
88
|
+
title: 'Company brief',
|
|
89
|
+
description: 'Aggregates current enrichment rows (comp / culture / recent_news) + jobs + warm intros for the company. ' +
|
|
90
|
+
'Chat client uses the returned structure to drive web research. With `notes` AND `kind` provided, the ' +
|
|
91
|
+
'api-mode summarises into enrichment for that single kind (refuses without kind — use enrich_company ' +
|
|
92
|
+
'directly to write multiple kinds at once).',
|
|
93
|
+
inputSchema: {
|
|
94
|
+
company: z.string().min(1),
|
|
95
|
+
kind: z.enum(['comp', 'culture', 'recent_news']).optional()
|
|
96
|
+
.describe('Required when persisting (mode=api + notes). Single kind per call to avoid writing the same summary to multiple rows.'),
|
|
97
|
+
notes: z.string().optional().describe('When provided + mode=api + kind, summarise into enrichment.'),
|
|
98
|
+
mode: z.enum(['chat', 'api']).default('chat'),
|
|
99
|
+
},
|
|
100
|
+
handler: async (args) => {
|
|
101
|
+
const db = getDb();
|
|
102
|
+
const found = findCompanyByName(args.company);
|
|
103
|
+
if (!found)
|
|
104
|
+
return errResult(`No company matching "${args.company}". Run scan_portals or seed companies first.`);
|
|
105
|
+
const c = db.prepare(`SELECT * FROM companies WHERE id = ?`).get(found.id);
|
|
106
|
+
const enrichments = db.prepare(`
|
|
107
|
+
SELECT kind, summary, confidence_score, signal_quality, expires_at, source_urls
|
|
108
|
+
FROM enrichment WHERE company_id = ?
|
|
109
|
+
`).all(c.id);
|
|
110
|
+
const topJobs = db.prepare(`
|
|
111
|
+
SELECT j.id, j.title, j.score_total, j.role_category, j.status, j.source_url
|
|
112
|
+
FROM jobs j WHERE j.company_id = ? ORDER BY j.score_total DESC NULLS LAST LIMIT 10
|
|
113
|
+
`).all(c.id);
|
|
114
|
+
const warmIntros = db.prepare(`
|
|
115
|
+
SELECT id, full_name, position, preferred_channel
|
|
116
|
+
FROM linkedin_connections WHERE company_id = ? AND is_recruiter = 0 LIMIT 25
|
|
117
|
+
`).all(c.id);
|
|
118
|
+
const h1b = db.prepare(`SELECT * FROM v_company_h1b_signal WHERE company_id = ?`).get(c.id);
|
|
119
|
+
if (args.mode === 'api' && args.notes) {
|
|
120
|
+
if (!args.kind)
|
|
121
|
+
return errResult('deep_research api+notes requires `kind` (comp|culture|recent_news). Use enrich_company directly to write multiple kinds.');
|
|
122
|
+
const system = 'You summarise web research about a company for a job candidate. Be skeptical: specific dollar figures + dates beat vague claims. ' +
|
|
123
|
+
'Output STRICT JSON: { summary: "<3 sentences", confidence_score: 0-100, signal_quality: "strong|mixed|weak|none", flags: "<comma-separated tags or none>" }.';
|
|
124
|
+
const user = JSON.stringify({ company: c.name, kind: args.kind, notes: args.notes.slice(0, 12_000) });
|
|
125
|
+
const call = await chatLogged('deep_research.api', [
|
|
126
|
+
{ role: 'system', content: system }, { role: 'user', content: user },
|
|
127
|
+
], { responseFormat: 'json_object', temperature: 0.3, maxTokens: 1500 });
|
|
128
|
+
if (call.parseOk && call.parsed) {
|
|
129
|
+
const p = call.parsed;
|
|
130
|
+
await runInWriteLock(() => {
|
|
131
|
+
getDb().prepare(`
|
|
132
|
+
INSERT INTO enrichment (id, company_id, kind, summary, confidence_score, signal_quality, flags, source_urls, expires_at)
|
|
133
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, '[]', datetime('now','+30 days'))
|
|
134
|
+
ON CONFLICT (company_id, kind) DO UPDATE SET
|
|
135
|
+
summary = excluded.summary,
|
|
136
|
+
confidence_score = excluded.confidence_score,
|
|
137
|
+
signal_quality = excluded.signal_quality,
|
|
138
|
+
flags = excluded.flags,
|
|
139
|
+
expires_at = excluded.expires_at
|
|
140
|
+
`).run(randomUUID(), c.id, args.kind, p.summary ?? null, p.confidence_score ?? null, p.signal_quality ?? null, p.flags ?? null);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return okResult({
|
|
145
|
+
company: { id: c.id, name: c.name, hq_city: c.hq_city, hq_country: c.hq_country,
|
|
146
|
+
headcount_range: c.headcount_range, funding_stage: c.funding_stage },
|
|
147
|
+
enrichments, top_jobs: topJobs, warm_intros: warmIntros, h1b_signal: h1b ?? null,
|
|
148
|
+
instructions: args.mode === 'chat' ? ('Use the company name to research comp, culture, recent_news. ' +
|
|
149
|
+
'Pull from Levels.fyi / Glassdoor / Blind / TechCrunch / news. ' +
|
|
150
|
+
'When done, call deep_research(company, kind, notes, mode=api) with notes containing the research blob.') : 'Persisted enrichment for the requested kind(s) if api+notes were provided.',
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
// ── daily_digest ─────────────────────────────────────────────────────────────
|
|
155
|
+
export const dailyDigestTool = defineTool({
|
|
156
|
+
name: 'daily_digest',
|
|
157
|
+
title: 'Morning summary',
|
|
158
|
+
description: 'Returns new top jobs since last digest, follow-ups due, pipeline state changes, and a cost snapshot. ' +
|
|
159
|
+
'Stamps digest_state.last_digest_at unless dry_run.',
|
|
160
|
+
inputSchema: {
|
|
161
|
+
dry_run: z.boolean().default(false),
|
|
162
|
+
min_score: z.number().int().min(0).max(100).default(75),
|
|
163
|
+
lookback_hours: z.number().int().min(1).max(720).optional()
|
|
164
|
+
.describe('Overrides "since last digest". Useful for the first run.'),
|
|
165
|
+
},
|
|
166
|
+
handler: async (args) => {
|
|
167
|
+
const db = getDb();
|
|
168
|
+
const lastRow = db.prepare(`SELECT last_digest_at FROM digest_state WHERE id = 1`).get();
|
|
169
|
+
const cutoff = args.lookback_hours
|
|
170
|
+
? new Date(Date.now() - args.lookback_hours * 3_600_000).toISOString()
|
|
171
|
+
: (lastRow?.last_digest_at ?? new Date(Date.now() - 24 * 3_600_000).toISOString());
|
|
172
|
+
const newTop = db.prepare(`
|
|
173
|
+
SELECT j.id, j.title, COALESCE(c.name, j.company_name_raw) AS company, j.score_total, j.source_url,
|
|
174
|
+
(SELECT er.html_path FROM eval_reports er WHERE er.job_id = j.id ORDER BY er.created_at DESC LIMIT 1) AS report_html
|
|
175
|
+
FROM jobs j LEFT JOIN companies c ON c.id = j.company_id
|
|
176
|
+
WHERE j.score_total >= ? AND datetime(j.discovered_at) >= datetime(?)
|
|
177
|
+
ORDER BY j.score_total DESC LIMIT 25
|
|
178
|
+
`).all(args.min_score, cutoff);
|
|
179
|
+
const followups = db.prepare(`SELECT * FROM v_followups_due ORDER BY datetime(followup_due_at) ASC LIMIT 25`).all();
|
|
180
|
+
const recentStatusChanges = db.prepare(`
|
|
181
|
+
SELECT j.id, j.title, COALESCE(c.name, j.company_name_raw) AS company, j.status, j.updated_at
|
|
182
|
+
FROM jobs j LEFT JOIN companies c ON c.id = j.company_id
|
|
183
|
+
WHERE datetime(j.updated_at) >= datetime(?) AND j.status IN ('applied','screen','onsite','offer','rejected','materials_drafted','ready_to_review')
|
|
184
|
+
ORDER BY datetime(j.updated_at) DESC LIMIT 25
|
|
185
|
+
`).all(cutoff);
|
|
186
|
+
const costRow = db.prepare(`
|
|
187
|
+
SELECT COUNT(*) AS calls, COALESCE(SUM(input_chars),0) AS in_chars, COALESCE(SUM(output_chars),0) AS out_chars
|
|
188
|
+
FROM llm_calls WHERE datetime(created_at) >= datetime(?)
|
|
189
|
+
`).get(cutoff);
|
|
190
|
+
if (!args.dry_run) {
|
|
191
|
+
await runInWriteLock(() => {
|
|
192
|
+
getDb().prepare(`UPDATE digest_state SET last_digest_at = CURRENT_TIMESTAMP WHERE id = 1`).run();
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return okResult({
|
|
196
|
+
since: cutoff,
|
|
197
|
+
new_top_jobs: newTop.map(j => ({
|
|
198
|
+
...j,
|
|
199
|
+
report_html: undefined,
|
|
200
|
+
report_url: j.report_html ? `${config.baseUrl}/files/${j.report_html}` : null,
|
|
201
|
+
})),
|
|
202
|
+
followups_due: followups,
|
|
203
|
+
status_changes: recentStatusChanges,
|
|
204
|
+
llm_cost_window: {
|
|
205
|
+
calls: costRow.calls, input_chars: costRow.in_chars, output_chars: costRow.out_chars,
|
|
206
|
+
},
|
|
207
|
+
tracker_url: `${config.baseUrl}/`,
|
|
208
|
+
});
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
// ── get_career_packet ────────────────────────────────────────────────────────
|
|
212
|
+
export const getCareerPacketTool = defineTool({
|
|
213
|
+
name: 'get_career_packet',
|
|
214
|
+
title: 'Get the active career packet',
|
|
215
|
+
description: 'Returns the active career_packet row (markdown + version + cv-hash).',
|
|
216
|
+
inputSchema: {},
|
|
217
|
+
handler: async () => {
|
|
218
|
+
const row = getActiveCareerPacket();
|
|
219
|
+
if (!row)
|
|
220
|
+
return errResult('No active career packet (server should seed on first run).');
|
|
221
|
+
return okResult(row);
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
// ── update_career_packet ─────────────────────────────────────────────────────
|
|
225
|
+
export const updateCareerPacketTool = defineTool({
|
|
226
|
+
name: 'update_career_packet',
|
|
227
|
+
title: 'Update the active career packet',
|
|
228
|
+
description: 'Replaces the active career packet content with a new version. Bumps version, retains history.',
|
|
229
|
+
inputSchema: {
|
|
230
|
+
content: z.string().min(50).describe('Full markdown content of the new packet.'),
|
|
231
|
+
notes: z.string().optional(),
|
|
232
|
+
},
|
|
233
|
+
handler: async (args) => {
|
|
234
|
+
const id = randomUUID();
|
|
235
|
+
const result = await runInWriteLock(() => {
|
|
236
|
+
const db = getDb();
|
|
237
|
+
const lastV = db.prepare(`SELECT COALESCE(MAX(version), 0) AS v FROM career_packet`).get().v;
|
|
238
|
+
const newV = lastV + 1;
|
|
239
|
+
db.prepare(`UPDATE career_packet SET is_active = 0 WHERE is_active = 1`).run();
|
|
240
|
+
const hash = createHash('sha256').update(args.content, 'utf-8').digest('hex');
|
|
241
|
+
db.prepare(`
|
|
242
|
+
INSERT INTO career_packet (id, version, content, is_active, source_cv_hash, notes)
|
|
243
|
+
VALUES (?, ?, ?, 1, ?, ?)
|
|
244
|
+
`).run(id, newV, args.content, hash, args.notes ?? null);
|
|
245
|
+
return { id, version: newV };
|
|
246
|
+
});
|
|
247
|
+
return okResult({ ...result, content_bytes: args.content.length });
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
// ── enrich_company ───────────────────────────────────────────────────────────
|
|
251
|
+
//
|
|
252
|
+
// Lightweight wrapper around deep_research(api) for a single (company, kind). Useful in
|
|
253
|
+
// chat for queueing a quick TTL refresh.
|
|
254
|
+
export const enrichCompanyTool = defineTool({
|
|
255
|
+
name: 'enrich_company',
|
|
256
|
+
title: 'Refresh enrichment row for a company',
|
|
257
|
+
description: 'Stores a chat- or api-provided enrichment summary for (company, kind) with a 30-day TTL.',
|
|
258
|
+
inputSchema: {
|
|
259
|
+
company: z.string().min(1),
|
|
260
|
+
kind: z.enum(['comp', 'culture', 'recent_news']),
|
|
261
|
+
summary: z.string().min(10),
|
|
262
|
+
confidence_score: z.number().int().min(0).max(100).default(60),
|
|
263
|
+
signal_quality: z.enum(['strong', 'mixed', 'weak', 'none']).default('mixed'),
|
|
264
|
+
source_urls: z.array(z.string()).default([]),
|
|
265
|
+
flags: z.string().optional(),
|
|
266
|
+
},
|
|
267
|
+
handler: async (args) => {
|
|
268
|
+
const c = findCompanyByName(args.company);
|
|
269
|
+
if (!c)
|
|
270
|
+
return errResult(`No company "${args.company}"`);
|
|
271
|
+
const id = await runInWriteLock(() => {
|
|
272
|
+
const id = randomUUID();
|
|
273
|
+
getDb().prepare(`
|
|
274
|
+
INSERT INTO enrichment (id, company_id, kind, summary, confidence_score, signal_quality, source_urls, flags, expires_at)
|
|
275
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now', '+30 days'))
|
|
276
|
+
ON CONFLICT (company_id, kind) DO UPDATE SET
|
|
277
|
+
summary = excluded.summary,
|
|
278
|
+
confidence_score = excluded.confidence_score,
|
|
279
|
+
signal_quality = excluded.signal_quality,
|
|
280
|
+
source_urls = excluded.source_urls,
|
|
281
|
+
flags = excluded.flags,
|
|
282
|
+
expires_at = excluded.expires_at
|
|
283
|
+
`).run(id, c.id, args.kind, args.summary, args.confidence_score, args.signal_quality, JSON.stringify(args.source_urls), args.flags ?? null);
|
|
284
|
+
return id;
|
|
285
|
+
});
|
|
286
|
+
return okResult({ company: c.name, kind: args.kind, enrichment_id: id, ttl_days: 30 });
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
// ── cost_estimate ────────────────────────────────────────────────────────────
|
|
290
|
+
export const costEstimateTool = defineTool({
|
|
291
|
+
name: 'cost_estimate',
|
|
292
|
+
title: 'LLM cost estimate',
|
|
293
|
+
description: 'Aggregates llm_calls by provider+model+tool over a window and estimates USD cost. Defaults: last 30 days.',
|
|
294
|
+
inputSchema: {
|
|
295
|
+
days: z.number().int().min(1).max(365).default(30),
|
|
296
|
+
},
|
|
297
|
+
handler: async (args) => {
|
|
298
|
+
// Compare ISO-8601 strings directly so the idx_llm_calls_created_at btree is usable.
|
|
299
|
+
const cutoff = new Date(Date.now() - args.days * 86_400_000).toISOString();
|
|
300
|
+
const rows = getDb().prepare(`
|
|
301
|
+
SELECT provider, model, tool, COUNT(*) AS calls,
|
|
302
|
+
SUM(input_chars) AS in_chars,
|
|
303
|
+
SUM(output_chars) AS out_chars,
|
|
304
|
+
SUM(CASE WHEN parse_ok = 0 THEN 1 ELSE 0 END) AS parse_errors,
|
|
305
|
+
SUM(duration_ms) AS ms
|
|
306
|
+
FROM llm_calls
|
|
307
|
+
WHERE created_at >= ?
|
|
308
|
+
GROUP BY provider, model, tool
|
|
309
|
+
ORDER BY ms DESC
|
|
310
|
+
`).all(cutoff);
|
|
311
|
+
let totalUsd = 0;
|
|
312
|
+
const items = rows.map(r => {
|
|
313
|
+
const usd = estimateCostUsd(r.model, Number(r.in_chars ?? 0), Number(r.out_chars ?? 0));
|
|
314
|
+
totalUsd += usd;
|
|
315
|
+
return { ...r, usd_estimate: round4(usd), rate: COST_TABLE[r.model] ?? null };
|
|
316
|
+
});
|
|
317
|
+
return okResult({ window_days: args.days, total_usd_estimate: round4(totalUsd), by_provider_model_tool: items });
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
function round4(n) { return Math.round(n * 10_000) / 10_000; }
|
|
321
|
+
//# sourceMappingURL=ops.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops.js","sourceRoot":"","sources":["../../../src/mcp/tools/ops.ts"],"names":[],"mappings":"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"}
|