trapic-mcp 0.1.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/LICENSE +21 -0
- package/README.md +152 -0
- package/bin/trapic-mcp.mjs +902 -0
- package/bin/wrapper.sh +5 -0
- package/dist/archive.d.ts +7 -0
- package/dist/archive.js +116 -0
- package/dist/audit.d.ts +5 -0
- package/dist/audit.js +16 -0
- package/dist/background.d.ts +8 -0
- package/dist/background.js +17 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.js +20 -0
- package/dist/conflict.d.ts +14 -0
- package/dist/conflict.js +103 -0
- package/dist/embedding.d.ts +6 -0
- package/dist/embedding.js +74 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +104 -0
- package/dist/llm.d.ts +10 -0
- package/dist/llm.js +47 -0
- package/dist/ollama.d.ts +11 -0
- package/dist/ollama.js +63 -0
- package/dist/quota.d.ts +7 -0
- package/dist/quota.js +16 -0
- package/dist/rate-limit.d.ts +5 -0
- package/dist/rate-limit.js +38 -0
- package/dist/request-context.d.ts +3 -0
- package/dist/request-context.js +12 -0
- package/dist/supabase.d.ts +2 -0
- package/dist/supabase.js +16 -0
- package/dist/team-access.d.ts +5 -0
- package/dist/team-access.js +35 -0
- package/dist/tools/active.d.ts +2 -0
- package/dist/tools/active.js +63 -0
- package/dist/tools/assert.d.ts +3 -0
- package/dist/tools/assert.js +141 -0
- package/dist/tools/chain.d.ts +2 -0
- package/dist/tools/chain.js +118 -0
- package/dist/tools/context.d.ts +7 -0
- package/dist/tools/context.js +270 -0
- package/dist/tools/create.d.ts +2 -0
- package/dist/tools/create.js +126 -0
- package/dist/tools/extract.d.ts +2 -0
- package/dist/tools/extract.js +95 -0
- package/dist/tools/preload.d.ts +10 -0
- package/dist/tools/preload.js +112 -0
- package/dist/tools/search.d.ts +2 -0
- package/dist/tools/search.js +92 -0
- package/dist/tools/summary.d.ts +2 -0
- package/dist/tools/summary.js +176 -0
- package/dist/tools/update.d.ts +2 -0
- package/dist/tools/update.js +134 -0
- package/dist/worker.d.ts +15 -0
- package/dist/worker.js +700 -0
- package/package.json +59 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getSupabase } from "../supabase.js";
|
|
3
|
+
import { generateEmbedding } from "../embedding.js";
|
|
4
|
+
import { audit } from "../audit.js";
|
|
5
|
+
import { getVisibleAuthors } from "../team-access.js";
|
|
6
|
+
export function registerSearch(server, userId) {
|
|
7
|
+
server.tool("trapic_search", "Semantic search for traces using natural language query. Combines vector similarity with optional tag/scope filtering. " +
|
|
8
|
+
"使用自然語言進行語意搜尋,結合向量相似度與標籤/範圍過濾。", {
|
|
9
|
+
query: z.string().describe("Natural language search query. " +
|
|
10
|
+
"自然語言搜尋查詢"),
|
|
11
|
+
tags: z.array(z.string()).optional().describe("Filter by tags (returns traces matching ANY of these tags). " +
|
|
12
|
+
"按標籤過濾(符合任一標籤即返回)"),
|
|
13
|
+
scope: z.enum(["personal", "team", "org"]).optional().describe("Filter by visibility scope. " +
|
|
14
|
+
"按可見範圍過濾"),
|
|
15
|
+
status: z.enum(["active", "superseded", "deprecated"]).default("active").describe("Filter by status (default: active). " +
|
|
16
|
+
"按狀態過濾(預設:active)"),
|
|
17
|
+
limit: z.number().int().min(1).max(50).default(10).describe("Maximum number of results (1-50, default: 10). " +
|
|
18
|
+
"最多返回筆數(1-50,預設 10)"),
|
|
19
|
+
threshold: z.number().min(0).max(1).default(0.7).describe("Minimum similarity threshold (0-1, default: 0.7). " +
|
|
20
|
+
"最低相似度閾值(0-1,預設 0.7)"),
|
|
21
|
+
}, async (params) => {
|
|
22
|
+
try {
|
|
23
|
+
const supabase = getSupabase();
|
|
24
|
+
// Generate query embedding
|
|
25
|
+
const queryEmbedding = await generateEmbedding(params.query);
|
|
26
|
+
// Call the search_traces RPC
|
|
27
|
+
const { data, error } = await supabase.rpc("search_traces", {
|
|
28
|
+
query_embedding: queryEmbedding,
|
|
29
|
+
filter_tags: params.tags ?? [],
|
|
30
|
+
filter_scope: params.scope ?? null,
|
|
31
|
+
filter_status: params.status,
|
|
32
|
+
match_limit: params.limit,
|
|
33
|
+
match_threshold: params.threshold,
|
|
34
|
+
});
|
|
35
|
+
if (error) {
|
|
36
|
+
return {
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
text: `Error searching traces: ${error.message}\n搜尋 Trace 失敗:${error.message}`,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Post-filter: show own traces + team members' traces
|
|
46
|
+
const visibleAuthors = userId ? await getVisibleAuthors(userId) : null;
|
|
47
|
+
const filtered = visibleAuthors
|
|
48
|
+
? (data ?? []).filter((row) => visibleAuthors.has(row.author))
|
|
49
|
+
: (data ?? []);
|
|
50
|
+
const results = filtered.map((row) => ({
|
|
51
|
+
id: row.id,
|
|
52
|
+
claim: row.claim,
|
|
53
|
+
reason: row.reason,
|
|
54
|
+
status: row.status,
|
|
55
|
+
tags: row.tags,
|
|
56
|
+
caused_by: row.caused_by,
|
|
57
|
+
confidence: row.confidence,
|
|
58
|
+
source: row.source,
|
|
59
|
+
author: row.author,
|
|
60
|
+
created_at: row.created_at,
|
|
61
|
+
similarity: typeof row.similarity === "number"
|
|
62
|
+
? Math.round(row.similarity * 1000) / 1000
|
|
63
|
+
: row.similarity,
|
|
64
|
+
}));
|
|
65
|
+
if (userId)
|
|
66
|
+
audit(userId, "trace.search", "trace", undefined, { query: params.query, results: results.length });
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: JSON.stringify({
|
|
72
|
+
query: params.query,
|
|
73
|
+
result_count: results.length,
|
|
74
|
+
results,
|
|
75
|
+
}, null, 2),
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
82
|
+
return {
|
|
83
|
+
content: [
|
|
84
|
+
{
|
|
85
|
+
type: "text",
|
|
86
|
+
text: `Error: ${message}`,
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getSupabase } from "../supabase.js";
|
|
3
|
+
import { generateEmbeddings } from "../embedding.js";
|
|
4
|
+
import { contextualizeTrace } from "./context.js";
|
|
5
|
+
import { llmChat } from "../llm.js";
|
|
6
|
+
import { checkMonthlyQuota } from "../quota.js";
|
|
7
|
+
const SUMMARY_EXTRACTION_PROMPT = `You are a knowledge extraction engine. Given a conversation summary, extract all key decisions, discoveries, and conclusions as Traces.
|
|
8
|
+
|
|
9
|
+
A Trace is a minimal causal proposition — one clear statement (claim) with an optional reason (why).
|
|
10
|
+
|
|
11
|
+
## What to extract
|
|
12
|
+
|
|
13
|
+
1. **Decisions** — what was decided and why
|
|
14
|
+
2. **Discoveries** — what was learned or realized
|
|
15
|
+
3. **Conclusions** — what was concluded from the discussion
|
|
16
|
+
|
|
17
|
+
## Rules
|
|
18
|
+
|
|
19
|
+
- Each trace = ONE proposition. Do not combine multiple ideas.
|
|
20
|
+
- claim = what happened / what was concluded (one clear sentence)
|
|
21
|
+
- reason = why (optional — some facts have no reason)
|
|
22
|
+
- Auto-assign tags based on content (e.g., "architecture", "design", "api", "performance", "security", "ux", "database", "deployment", "process", "decision")
|
|
23
|
+
- Be thorough but avoid extracting trivial or obvious statements
|
|
24
|
+
|
|
25
|
+
## Output format
|
|
26
|
+
|
|
27
|
+
Return JSON: { "traces": [{ "claim": "...", "reason": "..." or null, "tags": ["..."] }] }`;
|
|
28
|
+
export function registerSummary(server, userId) {
|
|
29
|
+
server.tool("trapic_auto_summary", "Extract and create multiple traces from a conversation summary in one call. " +
|
|
30
|
+
"Uses LLM to identify key decisions, discoveries, and conclusions, then writes them all to DB. " +
|
|
31
|
+
"從對話摘要中批次提取並建立多條 trace。", {
|
|
32
|
+
text: z.string().describe("Conversation summary text to extract traces from. 要提取 trace 的對話摘要文字"),
|
|
33
|
+
tags: z.array(z.string()).default([]).describe("Additional tags to apply to all created traces. 額外標籤(套用到所有建立的 trace)"),
|
|
34
|
+
source_id: z.string().optional().describe("Source reference ID (e.g. session ID). 來源參考 ID"),
|
|
35
|
+
}, async (params) => {
|
|
36
|
+
try {
|
|
37
|
+
if (!userId) {
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: "text", text: "Error: Authentication required." }],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const effectiveUserId = userId;
|
|
43
|
+
// Check monthly quota before doing LLM work
|
|
44
|
+
const quota = await checkMonthlyQuota(effectiveUserId);
|
|
45
|
+
if (!quota.allowed) {
|
|
46
|
+
return {
|
|
47
|
+
content: [{
|
|
48
|
+
type: "text",
|
|
49
|
+
text: `Monthly trace limit reached (${quota.used}/${quota.limit}). Resets next month.`,
|
|
50
|
+
}],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// 1. Use LLM to extract traces from summary
|
|
54
|
+
const content = await llmChat([
|
|
55
|
+
{ role: "system", content: SUMMARY_EXTRACTION_PROMPT },
|
|
56
|
+
{ role: "user", content: params.text },
|
|
57
|
+
]);
|
|
58
|
+
let extracted;
|
|
59
|
+
try {
|
|
60
|
+
const parsed = JSON.parse(content);
|
|
61
|
+
const rawTraces = Array.isArray(parsed) ? parsed : (parsed.traces ?? parsed.results ?? []);
|
|
62
|
+
extracted = rawTraces
|
|
63
|
+
.map((t) => ({
|
|
64
|
+
claim: String(t.claim ?? ""),
|
|
65
|
+
reason: t.reason ? String(t.reason) : null,
|
|
66
|
+
tags: Array.isArray(t.tags) ? t.tags.map(String) : [],
|
|
67
|
+
}))
|
|
68
|
+
.filter((t) => t.claim.trim().length > 0);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return {
|
|
72
|
+
content: [{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: `Error parsing LLM response. Raw output:\n${content}\n\nLLM 回應解析失敗。`,
|
|
75
|
+
}],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// Cap at 20 to prevent excessive insertions
|
|
79
|
+
extracted = extracted.slice(0, 20);
|
|
80
|
+
if (extracted.length === 0) {
|
|
81
|
+
return {
|
|
82
|
+
content: [{
|
|
83
|
+
type: "text",
|
|
84
|
+
text: JSON.stringify({
|
|
85
|
+
message: "No traces extracted from summary. 摘要中未提取到任何 trace。",
|
|
86
|
+
traces_created: 0,
|
|
87
|
+
}, null, 2),
|
|
88
|
+
}],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// 2. Truncate to remaining quota (use quota from initial check)
|
|
92
|
+
extracted = extracted.slice(0, Math.min(20, quota.remaining));
|
|
93
|
+
// 3. Batch generate embeddings, then create traces in DB
|
|
94
|
+
const supabase = getSupabase();
|
|
95
|
+
const created = [];
|
|
96
|
+
const errors = [];
|
|
97
|
+
// Batch embedding generation
|
|
98
|
+
const embeddingTexts = extracted.map((trace) => trace.reason ? `${trace.claim} ${trace.reason}` : trace.claim);
|
|
99
|
+
let embeddings;
|
|
100
|
+
try {
|
|
101
|
+
embeddings = await generateEmbeddings(embeddingTexts);
|
|
102
|
+
}
|
|
103
|
+
catch (embErr) {
|
|
104
|
+
const embMsg = embErr instanceof Error ? embErr.message : String(embErr);
|
|
105
|
+
return {
|
|
106
|
+
content: [{ type: "text", text: `Error generating embeddings: ${embMsg}` }],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// Insert traces in batches of 5
|
|
110
|
+
const BATCH_SIZE = 5;
|
|
111
|
+
for (let i = 0; i < extracted.length; i += BATCH_SIZE) {
|
|
112
|
+
const batch = extracted.slice(i, i + BATCH_SIZE);
|
|
113
|
+
const batchEmbeddings = embeddings.slice(i, i + BATCH_SIZE);
|
|
114
|
+
const results = await Promise.allSettled(batch.map(async (trace, idx) => {
|
|
115
|
+
// Merge user-provided tags with LLM-extracted tags
|
|
116
|
+
const mergedTags = [...new Set([...params.tags, ...trace.tags])];
|
|
117
|
+
// Insert into DB
|
|
118
|
+
const { data, error } = await supabase
|
|
119
|
+
.from("traces")
|
|
120
|
+
.insert({
|
|
121
|
+
claim: trace.claim,
|
|
122
|
+
reason: trace.reason,
|
|
123
|
+
scope: "personal",
|
|
124
|
+
author: effectiveUserId,
|
|
125
|
+
tags: mergedTags,
|
|
126
|
+
caused_by: [],
|
|
127
|
+
source: "extraction",
|
|
128
|
+
source_id: params.source_id ?? null,
|
|
129
|
+
confidence: "low",
|
|
130
|
+
references: [],
|
|
131
|
+
embedding: batchEmbeddings[idx],
|
|
132
|
+
})
|
|
133
|
+
.select()
|
|
134
|
+
.single();
|
|
135
|
+
if (error) {
|
|
136
|
+
throw new Error(`Failed to create trace "${trace.claim}": ${error.message}`);
|
|
137
|
+
}
|
|
138
|
+
// Contextualize (non-blocking failure)
|
|
139
|
+
await contextualizeTrace(data.id).catch(() => null);
|
|
140
|
+
return {
|
|
141
|
+
id: data.id,
|
|
142
|
+
claim: data.claim,
|
|
143
|
+
reason: data.reason,
|
|
144
|
+
tags: data.tags,
|
|
145
|
+
};
|
|
146
|
+
}));
|
|
147
|
+
for (const result of results) {
|
|
148
|
+
if (result.status === "fulfilled") {
|
|
149
|
+
created.push(result.value);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
errors.push(result.reason?.message ?? String(result.reason));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
content: [{
|
|
158
|
+
type: "text",
|
|
159
|
+
text: JSON.stringify({
|
|
160
|
+
message: `Created ${created.length} trace(s) from summary. 從摘要建立了 ${created.length} 條 trace。`,
|
|
161
|
+
traces_created: created.length,
|
|
162
|
+
traces_extracted: extracted.length,
|
|
163
|
+
traces: created,
|
|
164
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
165
|
+
}, null, 2),
|
|
166
|
+
}],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
171
|
+
return {
|
|
172
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getSupabase } from "../supabase.js";
|
|
3
|
+
import { generateEmbedding } from "../embedding.js";
|
|
4
|
+
import { audit } from "../audit.js";
|
|
5
|
+
export function registerUpdate(server, userId) {
|
|
6
|
+
server.tool("trapic_update", "Update an existing trace — change status, tags, claim/reason, or mark as superseded. " +
|
|
7
|
+
"更新現有 trace — 可以變更狀態、標籤、claim/reason,或標記為被取代。", {
|
|
8
|
+
trace_id: z.string().uuid().describe("ID of the trace to update. " +
|
|
9
|
+
"要更新的 trace ID"),
|
|
10
|
+
claim: z.string().optional().describe("Updated claim text. Will regenerate embedding if changed. " +
|
|
11
|
+
"更新的 claim 文字。如果變更會重新產生 embedding"),
|
|
12
|
+
reason: z.string().optional().describe("Updated reason text. Will regenerate embedding if changed. " +
|
|
13
|
+
"更新的 reason 文字。如果變更會重新產生 embedding"),
|
|
14
|
+
status: z.enum(["active", "superseded", "deprecated"]).optional().describe("New status for the trace. " +
|
|
15
|
+
"trace 的新狀態"),
|
|
16
|
+
superseded_by: z.string().uuid().optional().describe("ID of the trace that supersedes this one (sets status to 'superseded' automatically). " +
|
|
17
|
+
"取代此 trace 的新 trace ID(會自動將狀態設為 superseded)"),
|
|
18
|
+
tags: z.array(z.string()).optional().describe("Replace tags with this new list. " +
|
|
19
|
+
"用新的標籤列表替換"),
|
|
20
|
+
confidence: z.enum(["high", "medium", "low"]).optional().describe("Updated confidence level. " +
|
|
21
|
+
"更新的信心程度"),
|
|
22
|
+
references: z.array(z.string()).optional().describe("Replace references with this new list. " +
|
|
23
|
+
"用新的參考連結列表替換"),
|
|
24
|
+
}, async (params) => {
|
|
25
|
+
try {
|
|
26
|
+
const supabase = getSupabase();
|
|
27
|
+
// Build update object with only provided fields
|
|
28
|
+
const update = {};
|
|
29
|
+
if (params.claim !== undefined)
|
|
30
|
+
update.claim = params.claim;
|
|
31
|
+
if (params.reason !== undefined)
|
|
32
|
+
update.reason = params.reason;
|
|
33
|
+
if (params.tags !== undefined)
|
|
34
|
+
update.tags = params.tags;
|
|
35
|
+
if (params.confidence !== undefined)
|
|
36
|
+
update.confidence = params.confidence;
|
|
37
|
+
if (params.references !== undefined)
|
|
38
|
+
update.references = params.references;
|
|
39
|
+
// Handle superseded_by — auto-set status
|
|
40
|
+
if (params.superseded_by !== undefined) {
|
|
41
|
+
update.superseded_by = params.superseded_by;
|
|
42
|
+
update.status = "superseded";
|
|
43
|
+
}
|
|
44
|
+
else if (params.status !== undefined) {
|
|
45
|
+
update.status = params.status;
|
|
46
|
+
}
|
|
47
|
+
// Regenerate embedding if claim or reason changed
|
|
48
|
+
if (params.claim !== undefined || params.reason !== undefined) {
|
|
49
|
+
// Fetch current trace to get existing claim/reason if only one changed
|
|
50
|
+
let query = supabase
|
|
51
|
+
.from("traces")
|
|
52
|
+
.select("claim, reason")
|
|
53
|
+
.eq("id", params.trace_id);
|
|
54
|
+
if (userId)
|
|
55
|
+
query = query.eq("author", userId);
|
|
56
|
+
const { data: current, error: fetchError } = await query.single();
|
|
57
|
+
if (fetchError) {
|
|
58
|
+
return {
|
|
59
|
+
content: [
|
|
60
|
+
{
|
|
61
|
+
type: "text",
|
|
62
|
+
text: `Error fetching current trace: ${fetchError.message}\n取得現有 trace 失敗:${fetchError.message}`,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const newClaim = params.claim ?? current.claim;
|
|
68
|
+
const newReason = params.reason ?? current.reason;
|
|
69
|
+
const embeddingText = newReason
|
|
70
|
+
? `${newClaim} ${newReason}`
|
|
71
|
+
: newClaim;
|
|
72
|
+
update.embedding = await generateEmbedding(embeddingText);
|
|
73
|
+
}
|
|
74
|
+
if (Object.keys(update).length === 0) {
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: "text",
|
|
79
|
+
text: "No fields to update. Provide at least one field to change.\n沒有要更新的欄位,請至少提供一個要變更的欄位。",
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
let updateQuery = supabase
|
|
85
|
+
.from("traces")
|
|
86
|
+
.update(update)
|
|
87
|
+
.eq("id", params.trace_id);
|
|
88
|
+
if (userId)
|
|
89
|
+
updateQuery = updateQuery.eq("author", userId);
|
|
90
|
+
const { data, error } = await updateQuery
|
|
91
|
+
.select()
|
|
92
|
+
.single();
|
|
93
|
+
if (error) {
|
|
94
|
+
return {
|
|
95
|
+
content: [
|
|
96
|
+
{
|
|
97
|
+
type: "text",
|
|
98
|
+
text: `Error updating trace: ${error.message}\n更新 trace 失敗:${error.message}`,
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (userId)
|
|
104
|
+
audit(userId, "trace.update", "trace", params.trace_id);
|
|
105
|
+
return {
|
|
106
|
+
content: [
|
|
107
|
+
{
|
|
108
|
+
type: "text",
|
|
109
|
+
text: JSON.stringify({
|
|
110
|
+
success: true,
|
|
111
|
+
message: "Trace updated successfully / Trace 更新成功",
|
|
112
|
+
trace: {
|
|
113
|
+
id: data.id,
|
|
114
|
+
claim: data.claim,
|
|
115
|
+
reason: data.reason,
|
|
116
|
+
status: data.status,
|
|
117
|
+
superseded_by: data.superseded_by,
|
|
118
|
+
tags: data.tags,
|
|
119
|
+
confidence: data.confidence,
|
|
120
|
+
updated_at: data.updated_at,
|
|
121
|
+
},
|
|
122
|
+
}, null, 2),
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
129
|
+
return {
|
|
130
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface Env {
|
|
2
|
+
SUPABASE_URL: string;
|
|
3
|
+
SUPABASE_SERVICE_ROLE_KEY: string;
|
|
4
|
+
OPENAI_API_KEY: string;
|
|
5
|
+
OPENAI_EMBED_MODEL?: string;
|
|
6
|
+
GROQ_API_KEY?: string;
|
|
7
|
+
GROQ_CHAT_MODEL?: string;
|
|
8
|
+
ARCHIVE_BUCKET: R2Bucket;
|
|
9
|
+
RESEND_API_KEY?: string;
|
|
10
|
+
}
|
|
11
|
+
declare const _default: {
|
|
12
|
+
fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response>;
|
|
13
|
+
scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
export default _default;
|