@steno-ai/mcp 0.1.3 → 0.1.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.
- package/dist/cli.js +830 -921
- package/package.json +3 -5
- package/src/cli.ts +10 -46
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
#!/usr/bin/env node
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __esm = (fn, res) => function __init() {
|
|
@@ -24753,887 +24753,6 @@ var init_manager = __esm({
|
|
|
24753
24753
|
}
|
|
24754
24754
|
});
|
|
24755
24755
|
|
|
24756
|
-
// packages/supabase-adapter/src/storage.js
|
|
24757
|
-
function camelToSnake(key) {
|
|
24758
|
-
return key.replace(/([A-Z])/g, (match2) => `_${match2.toLowerCase()}`);
|
|
24759
|
-
}
|
|
24760
|
-
function snakeToCamel(key) {
|
|
24761
|
-
return key.replace(/_([a-z])/g, (_2, char) => char.toUpperCase());
|
|
24762
|
-
}
|
|
24763
|
-
function toSnakeCase(obj) {
|
|
24764
|
-
const result = {};
|
|
24765
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
24766
|
-
result[camelToSnake(key)] = value;
|
|
24767
|
-
}
|
|
24768
|
-
return result;
|
|
24769
|
-
}
|
|
24770
|
-
function toCamelCase(obj) {
|
|
24771
|
-
const result = {};
|
|
24772
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
24773
|
-
result[snakeToCamel(key)] = value;
|
|
24774
|
-
}
|
|
24775
|
-
return result;
|
|
24776
|
-
}
|
|
24777
|
-
function throwSupabaseError(method, error) {
|
|
24778
|
-
throw new Error(`SupabaseStorageAdapter.${method}() failed: ${error?.message ?? "unknown error"}`);
|
|
24779
|
-
}
|
|
24780
|
-
var SupabaseStorageAdapter;
|
|
24781
|
-
var init_storage = __esm({
|
|
24782
|
-
"packages/supabase-adapter/src/storage.js"() {
|
|
24783
|
-
"use strict";
|
|
24784
|
-
SupabaseStorageAdapter = class {
|
|
24785
|
-
client;
|
|
24786
|
-
constructor(client) {
|
|
24787
|
-
this.client = client;
|
|
24788
|
-
}
|
|
24789
|
-
async ping() {
|
|
24790
|
-
const { error } = await this.client.from("tenants").select("id").limit(1);
|
|
24791
|
-
return !error;
|
|
24792
|
-
}
|
|
24793
|
-
// ---------------------------------------------------------------------------
|
|
24794
|
-
// Tenants
|
|
24795
|
-
// ---------------------------------------------------------------------------
|
|
24796
|
-
async createTenant(tenant) {
|
|
24797
|
-
const row = toSnakeCase(tenant);
|
|
24798
|
-
const { data, error } = await this.client.from("tenants").insert(row).select().single();
|
|
24799
|
-
if (error)
|
|
24800
|
-
throwSupabaseError("createTenant", error);
|
|
24801
|
-
return toCamelCase(data);
|
|
24802
|
-
}
|
|
24803
|
-
async getTenant(id) {
|
|
24804
|
-
const { data, error } = await this.client.from("tenants").select("*").eq("id", id).maybeSingle();
|
|
24805
|
-
if (error)
|
|
24806
|
-
throwSupabaseError("getTenant", error);
|
|
24807
|
-
if (!data)
|
|
24808
|
-
return null;
|
|
24809
|
-
return toCamelCase(data);
|
|
24810
|
-
}
|
|
24811
|
-
async getTenantBySlug(slug) {
|
|
24812
|
-
const { data, error } = await this.client.from("tenants").select("*").eq("slug", slug).maybeSingle();
|
|
24813
|
-
if (error)
|
|
24814
|
-
throwSupabaseError("getTenantBySlug", error);
|
|
24815
|
-
if (!data)
|
|
24816
|
-
return null;
|
|
24817
|
-
return toCamelCase(data);
|
|
24818
|
-
}
|
|
24819
|
-
async updateTenant(id, updates) {
|
|
24820
|
-
const row = toSnakeCase(updates);
|
|
24821
|
-
const { data, error } = await this.client.from("tenants").update(row).eq("id", id).select().single();
|
|
24822
|
-
if (error)
|
|
24823
|
-
throwSupabaseError("updateTenant", error);
|
|
24824
|
-
return toCamelCase(data);
|
|
24825
|
-
}
|
|
24826
|
-
// ---------------------------------------------------------------------------
|
|
24827
|
-
// API Keys
|
|
24828
|
-
// ---------------------------------------------------------------------------
|
|
24829
|
-
async createApiKey(apiKey) {
|
|
24830
|
-
const row = toSnakeCase(apiKey);
|
|
24831
|
-
const { data, error } = await this.client.from("api_keys").insert(row).select().single();
|
|
24832
|
-
if (error)
|
|
24833
|
-
throwSupabaseError("createApiKey", error);
|
|
24834
|
-
return toCamelCase(data);
|
|
24835
|
-
}
|
|
24836
|
-
async getApiKeyByPrefix(prefix5) {
|
|
24837
|
-
const { data, error } = await this.client.from("api_keys").select("*").eq("key_prefix", prefix5).eq("active", true).maybeSingle();
|
|
24838
|
-
if (error)
|
|
24839
|
-
throwSupabaseError("getApiKeyByPrefix", error);
|
|
24840
|
-
if (!data)
|
|
24841
|
-
return null;
|
|
24842
|
-
return toCamelCase(data);
|
|
24843
|
-
}
|
|
24844
|
-
async getApiKeysForTenant(tenantId) {
|
|
24845
|
-
const { data, error } = await this.client.from("api_keys").select("*").eq("tenant_id", tenantId);
|
|
24846
|
-
if (error)
|
|
24847
|
-
throwSupabaseError("getApiKeysForTenant", error);
|
|
24848
|
-
return (data ?? []).map((row) => toCamelCase(row));
|
|
24849
|
-
}
|
|
24850
|
-
async revokeApiKey(tenantId, id) {
|
|
24851
|
-
const { error } = await this.client.from("api_keys").update({ active: false }).eq("id", id).eq("tenant_id", tenantId);
|
|
24852
|
-
if (error)
|
|
24853
|
-
throwSupabaseError("revokeApiKey", error);
|
|
24854
|
-
}
|
|
24855
|
-
async updateApiKeyLastUsed(id) {
|
|
24856
|
-
const { error } = await this.client.from("api_keys").update({ last_used_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", id);
|
|
24857
|
-
if (error)
|
|
24858
|
-
throwSupabaseError("updateApiKeyLastUsed", error);
|
|
24859
|
-
}
|
|
24860
|
-
// ---------------------------------------------------------------------------
|
|
24861
|
-
// Extractions
|
|
24862
|
-
// ---------------------------------------------------------------------------
|
|
24863
|
-
async createExtraction(extraction) {
|
|
24864
|
-
const row = toSnakeCase({
|
|
24865
|
-
...extraction,
|
|
24866
|
-
status: "queued"
|
|
24867
|
-
});
|
|
24868
|
-
const { data, error } = await this.client.from("extractions").insert(row).select().single();
|
|
24869
|
-
if (error)
|
|
24870
|
-
throwSupabaseError("createExtraction", error);
|
|
24871
|
-
return toCamelCase(data);
|
|
24872
|
-
}
|
|
24873
|
-
async getExtraction(tenantId, id) {
|
|
24874
|
-
const { data, error } = await this.client.from("extractions").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
24875
|
-
if (error)
|
|
24876
|
-
throwSupabaseError("getExtraction", error);
|
|
24877
|
-
if (!data)
|
|
24878
|
-
return null;
|
|
24879
|
-
return toCamelCase(data);
|
|
24880
|
-
}
|
|
24881
|
-
async updateExtraction(tenantId, id, updates) {
|
|
24882
|
-
const row = toSnakeCase(updates);
|
|
24883
|
-
const { data, error } = await this.client.from("extractions").update(row).eq("tenant_id", tenantId).eq("id", id).select().single();
|
|
24884
|
-
if (error)
|
|
24885
|
-
throwSupabaseError("updateExtraction", error);
|
|
24886
|
-
return toCamelCase(data);
|
|
24887
|
-
}
|
|
24888
|
-
async getExtractionByHash(tenantId, inputHash) {
|
|
24889
|
-
const { data, error } = await this.client.from("extractions").select("*").eq("tenant_id", tenantId).eq("input_hash", inputHash).maybeSingle();
|
|
24890
|
-
if (error)
|
|
24891
|
-
throwSupabaseError("getExtractionByHash", error);
|
|
24892
|
-
if (!data)
|
|
24893
|
-
return null;
|
|
24894
|
-
return toCamelCase(data);
|
|
24895
|
-
}
|
|
24896
|
-
async getExtractionsByTenant(tenantId, options) {
|
|
24897
|
-
const { limit, cursor } = options;
|
|
24898
|
-
let query = this.client.from("extractions").select("*").eq("tenant_id", tenantId).order("created_at", { ascending: false }).limit(limit + 1);
|
|
24899
|
-
if (cursor) {
|
|
24900
|
-
query = query.lt("created_at", cursor);
|
|
24901
|
-
}
|
|
24902
|
-
const { data, error } = await query;
|
|
24903
|
-
if (error)
|
|
24904
|
-
throwSupabaseError("getExtractionsByTenant", error);
|
|
24905
|
-
const rows = data ?? [];
|
|
24906
|
-
const hasMore = rows.length > limit;
|
|
24907
|
-
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
24908
|
-
const extractions = page.map((row) => toCamelCase(row));
|
|
24909
|
-
const nextCursor = hasMore && page.length > 0 ? page[page.length - 1]["created_at"] : null;
|
|
24910
|
-
return { data: extractions, cursor: nextCursor, hasMore };
|
|
24911
|
-
}
|
|
24912
|
-
// ---------------------------------------------------------------------------
|
|
24913
|
-
// Facts
|
|
24914
|
-
// ---------------------------------------------------------------------------
|
|
24915
|
-
async createFact(fact) {
|
|
24916
|
-
const { embedding, ...rest } = fact;
|
|
24917
|
-
const row = toSnakeCase(rest);
|
|
24918
|
-
if (!("version" in row)) {
|
|
24919
|
-
row["version"] = 1;
|
|
24920
|
-
}
|
|
24921
|
-
if (!row["lineage_id"]) {
|
|
24922
|
-
row["lineage_id"] = fact.id;
|
|
24923
|
-
}
|
|
24924
|
-
if (embedding !== void 0) {
|
|
24925
|
-
row["embedding"] = `[${embedding.join(",")}]`;
|
|
24926
|
-
}
|
|
24927
|
-
const { data, error } = await this.client.from("facts").insert(row).select().single();
|
|
24928
|
-
if (error)
|
|
24929
|
-
throwSupabaseError("createFact", error);
|
|
24930
|
-
return toCamelCase(data);
|
|
24931
|
-
}
|
|
24932
|
-
async getFact(tenantId, id) {
|
|
24933
|
-
const { data, error } = await this.client.from("facts").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
24934
|
-
if (error)
|
|
24935
|
-
throwSupabaseError("getFact", error);
|
|
24936
|
-
if (!data)
|
|
24937
|
-
return null;
|
|
24938
|
-
return toCamelCase(data);
|
|
24939
|
-
}
|
|
24940
|
-
async getFactsByIds(tenantId, ids) {
|
|
24941
|
-
if (ids.length === 0)
|
|
24942
|
-
return [];
|
|
24943
|
-
const { data, error } = await this.client.from("facts").select("*").eq("tenant_id", tenantId).in("id", ids);
|
|
24944
|
-
if (error)
|
|
24945
|
-
throwSupabaseError("getFactsByIds", error);
|
|
24946
|
-
return (data ?? []).map((row) => toCamelCase(row));
|
|
24947
|
-
}
|
|
24948
|
-
async getFactsByLineage(tenantId, lineageId) {
|
|
24949
|
-
const { data, error } = await this.client.from("facts").select("*").eq("tenant_id", tenantId).eq("lineage_id", lineageId).order("version", { ascending: true });
|
|
24950
|
-
if (error)
|
|
24951
|
-
throwSupabaseError("getFactsByLineage", error);
|
|
24952
|
-
return (data ?? []).map((row) => toCamelCase(row));
|
|
24953
|
-
}
|
|
24954
|
-
async invalidateFact(tenantId, id) {
|
|
24955
|
-
const { error } = await this.client.from("facts").update({ valid_until: (/* @__PURE__ */ new Date()).toISOString() }).eq("tenant_id", tenantId).eq("id", id);
|
|
24956
|
-
if (error)
|
|
24957
|
-
throwSupabaseError("invalidateFact", error);
|
|
24958
|
-
}
|
|
24959
|
-
// ---------------------------------------------------------------------------
|
|
24960
|
-
// Entities
|
|
24961
|
-
// ---------------------------------------------------------------------------
|
|
24962
|
-
async createEntity(entity2) {
|
|
24963
|
-
const { embedding, ...rest } = entity2;
|
|
24964
|
-
const row = toSnakeCase(rest);
|
|
24965
|
-
if (embedding !== void 0) {
|
|
24966
|
-
row["embedding"] = `[${embedding.join(",")}]`;
|
|
24967
|
-
}
|
|
24968
|
-
const { data, error } = await this.client.from("entities").insert(row).select().single();
|
|
24969
|
-
if (error)
|
|
24970
|
-
throwSupabaseError("createEntity", error);
|
|
24971
|
-
return toCamelCase(data);
|
|
24972
|
-
}
|
|
24973
|
-
async getEntity(tenantId, id) {
|
|
24974
|
-
const { data, error } = await this.client.from("entities").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
24975
|
-
if (error)
|
|
24976
|
-
throwSupabaseError("getEntity", error);
|
|
24977
|
-
if (!data)
|
|
24978
|
-
return null;
|
|
24979
|
-
return toCamelCase(data);
|
|
24980
|
-
}
|
|
24981
|
-
async findEntityByCanonicalName(tenantId, canonicalName, entityType) {
|
|
24982
|
-
const { data, error } = await this.client.from("entities").select("*").eq("tenant_id", tenantId).eq("canonical_name", canonicalName).eq("entity_type", entityType).maybeSingle();
|
|
24983
|
-
if (error)
|
|
24984
|
-
throwSupabaseError("findEntityByCanonicalName", error);
|
|
24985
|
-
if (!data)
|
|
24986
|
-
return null;
|
|
24987
|
-
return toCamelCase(data);
|
|
24988
|
-
}
|
|
24989
|
-
async findEntitiesByEmbedding(tenantId, embedding, limit, minSimilarity = 0.3) {
|
|
24990
|
-
const { data, error } = await this.client.rpc("match_entities", {
|
|
24991
|
-
query_embedding: JSON.stringify(embedding),
|
|
24992
|
-
match_tenant_id: tenantId,
|
|
24993
|
-
match_count: limit,
|
|
24994
|
-
min_similarity: minSimilarity
|
|
24995
|
-
});
|
|
24996
|
-
if (error)
|
|
24997
|
-
throwSupabaseError("findEntitiesByEmbedding", error);
|
|
24998
|
-
return (data ?? []).map((row) => ({
|
|
24999
|
-
entity: toCamelCase(row),
|
|
25000
|
-
similarity: row["similarity"]
|
|
25001
|
-
}));
|
|
25002
|
-
}
|
|
25003
|
-
// ---------------------------------------------------------------------------
|
|
25004
|
-
// Fact-Entity junction
|
|
25005
|
-
// ---------------------------------------------------------------------------
|
|
25006
|
-
async linkFactEntity(factId, entityId, role) {
|
|
25007
|
-
const { error } = await this.client.from("fact_entities").insert({
|
|
25008
|
-
fact_id: factId,
|
|
25009
|
-
entity_id: entityId,
|
|
25010
|
-
role
|
|
25011
|
-
});
|
|
25012
|
-
if (error)
|
|
25013
|
-
throwSupabaseError("linkFactEntity", error);
|
|
25014
|
-
}
|
|
25015
|
-
// ---------------------------------------------------------------------------
|
|
25016
|
-
// Edges
|
|
25017
|
-
// ---------------------------------------------------------------------------
|
|
25018
|
-
async createEdge(edge) {
|
|
25019
|
-
const row = toSnakeCase(edge);
|
|
25020
|
-
const { data, error } = await this.client.from("edges").insert(row).select().single();
|
|
25021
|
-
if (error)
|
|
25022
|
-
throwSupabaseError("createEdge", error);
|
|
25023
|
-
return toCamelCase(data);
|
|
25024
|
-
}
|
|
25025
|
-
// ---------------------------------------------------------------------------
|
|
25026
|
-
// Vector search
|
|
25027
|
-
// ---------------------------------------------------------------------------
|
|
25028
|
-
async vectorSearch(options) {
|
|
25029
|
-
const { embedding, tenantId, scope, scopeId, limit, minSimilarity } = options;
|
|
25030
|
-
const { data, error } = await this.client.rpc("match_facts", {
|
|
25031
|
-
query_embedding: `[${embedding.join(",")}]`,
|
|
25032
|
-
match_tenant_id: tenantId,
|
|
25033
|
-
match_scope: scope,
|
|
25034
|
-
match_scope_id: scopeId,
|
|
25035
|
-
match_count: limit,
|
|
25036
|
-
min_similarity: minSimilarity ?? 0,
|
|
25037
|
-
match_as_of: options.asOf?.toISOString() ?? null
|
|
25038
|
-
});
|
|
25039
|
-
if (error)
|
|
25040
|
-
throwSupabaseError("vectorSearch", error);
|
|
25041
|
-
return (data ?? []).map((row) => ({
|
|
25042
|
-
fact: toCamelCase(row),
|
|
25043
|
-
similarity: row["similarity"]
|
|
25044
|
-
}));
|
|
25045
|
-
}
|
|
25046
|
-
// ---------------------------------------------------------------------------
|
|
25047
|
-
// Usage
|
|
25048
|
-
// ---------------------------------------------------------------------------
|
|
25049
|
-
async incrementUsage(tenantId, tokens, queries, extractions, costUsd) {
|
|
25050
|
-
const { error } = await this.client.rpc("increment_usage", {
|
|
25051
|
-
p_tenant_id: tenantId,
|
|
25052
|
-
p_tokens: tokens,
|
|
25053
|
-
p_queries: queries,
|
|
25054
|
-
p_extractions: extractions,
|
|
25055
|
-
p_cost_usd: costUsd
|
|
25056
|
-
});
|
|
25057
|
-
if (error)
|
|
25058
|
-
throwSupabaseError("incrementUsage", error);
|
|
25059
|
-
}
|
|
25060
|
-
async getUsage(tenantId, periodStart) {
|
|
25061
|
-
const { data, error } = await this.client.from("usage_records").select("*").eq("tenant_id", tenantId).eq("period_start", periodStart.toISOString()).maybeSingle();
|
|
25062
|
-
if (error)
|
|
25063
|
-
throwSupabaseError("getUsage", error);
|
|
25064
|
-
if (!data)
|
|
25065
|
-
return null;
|
|
25066
|
-
return toCamelCase(data);
|
|
25067
|
-
}
|
|
25068
|
-
async getCurrentUsage(tenantId) {
|
|
25069
|
-
const now = /* @__PURE__ */ new Date();
|
|
25070
|
-
const periodStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
25071
|
-
return this.getUsage(tenantId, periodStart);
|
|
25072
|
-
}
|
|
25073
|
-
// ---------------------------------------------------------------------------
|
|
25074
|
-
// Stubs — implemented in Plan 3 (Retrieval Engine)
|
|
25075
|
-
// ---------------------------------------------------------------------------
|
|
25076
|
-
async getFactsByScope(tenantId, scope, scopeId, options) {
|
|
25077
|
-
const { limit, cursor } = options;
|
|
25078
|
-
let query = this.client.from("facts").select("*").eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId).order("created_at", { ascending: false }).limit(limit + 1);
|
|
25079
|
-
if (cursor) {
|
|
25080
|
-
query = query.lt("created_at", cursor);
|
|
25081
|
-
}
|
|
25082
|
-
const { data, error } = await query;
|
|
25083
|
-
if (error)
|
|
25084
|
-
throwSupabaseError("getFactsByScope", error);
|
|
25085
|
-
const rows = data ?? [];
|
|
25086
|
-
const hasMore = rows.length > limit;
|
|
25087
|
-
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
25088
|
-
const facts = page.map((row) => toCamelCase(row));
|
|
25089
|
-
const nextCursor = hasMore && page.length > 0 ? page[page.length - 1]["created_at"] : null;
|
|
25090
|
-
return { data: facts, cursor: nextCursor, hasMore };
|
|
25091
|
-
}
|
|
25092
|
-
async purgeFacts(tenantId, scope, scopeId) {
|
|
25093
|
-
const { data: factRows, error: fetchError } = await this.client.from("facts").select("id").eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId);
|
|
25094
|
-
if (fetchError)
|
|
25095
|
-
throwSupabaseError("purgeFacts", fetchError);
|
|
25096
|
-
const factIds = (factRows ?? []).map((row) => row["id"]);
|
|
25097
|
-
if (factIds.length === 0)
|
|
25098
|
-
return 0;
|
|
25099
|
-
const { error: feError } = await this.client.from("fact_entities").delete().in("fact_id", factIds);
|
|
25100
|
-
if (feError)
|
|
25101
|
-
throwSupabaseError("purgeFacts", feError);
|
|
25102
|
-
const { error: edgeError } = await this.client.from("edges").delete().in("fact_id", factIds);
|
|
25103
|
-
if (edgeError)
|
|
25104
|
-
throwSupabaseError("purgeFacts", edgeError);
|
|
25105
|
-
const { error: deleteError } = await this.client.from("facts").delete().eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId);
|
|
25106
|
-
if (deleteError)
|
|
25107
|
-
throwSupabaseError("purgeFacts", deleteError);
|
|
25108
|
-
const { error: extractionError } = await this.client.from("extractions").delete().eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId);
|
|
25109
|
-
if (extractionError)
|
|
25110
|
-
throwSupabaseError("purgeFacts", extractionError);
|
|
25111
|
-
return factIds.length;
|
|
25112
|
-
}
|
|
25113
|
-
async updateDecayScores(tenantId, facts) {
|
|
25114
|
-
for (const fact of facts) {
|
|
25115
|
-
const updates = {
|
|
25116
|
-
decay_score: fact.decayScore
|
|
25117
|
-
};
|
|
25118
|
-
if (fact.lastAccessed !== void 0) {
|
|
25119
|
-
updates["last_accessed"] = fact.lastAccessed.toISOString();
|
|
25120
|
-
}
|
|
25121
|
-
if (fact.frequency !== void 0) {
|
|
25122
|
-
updates["frequency"] = fact.frequency;
|
|
25123
|
-
}
|
|
25124
|
-
if (fact.importance !== void 0) {
|
|
25125
|
-
updates["importance"] = fact.importance;
|
|
25126
|
-
}
|
|
25127
|
-
const { error } = await this.client.from("facts").update(updates).eq("tenant_id", tenantId).eq("id", fact.id);
|
|
25128
|
-
if (error)
|
|
25129
|
-
throwSupabaseError("updateDecayScores", error);
|
|
25130
|
-
}
|
|
25131
|
-
}
|
|
25132
|
-
async keywordSearch(options) {
|
|
25133
|
-
const { query, tenantId, scope, scopeId, limit, asOf } = options;
|
|
25134
|
-
const { data, error } = await this.client.rpc("keyword_search_facts", {
|
|
25135
|
-
search_query: query,
|
|
25136
|
-
match_tenant_id: tenantId,
|
|
25137
|
-
match_scope: scope,
|
|
25138
|
-
match_scope_id: scopeId,
|
|
25139
|
-
match_count: limit,
|
|
25140
|
-
match_as_of: asOf?.toISOString() ?? null
|
|
25141
|
-
});
|
|
25142
|
-
if (error)
|
|
25143
|
-
throwSupabaseError("keywordSearch", error);
|
|
25144
|
-
return (data ?? []).map((row) => {
|
|
25145
|
-
const rankScore = row["rank_score"];
|
|
25146
|
-
const converted = toCamelCase(row);
|
|
25147
|
-
return {
|
|
25148
|
-
fact: converted,
|
|
25149
|
-
rankScore
|
|
25150
|
-
};
|
|
25151
|
-
});
|
|
25152
|
-
}
|
|
25153
|
-
async compoundSearch(options) {
|
|
25154
|
-
const { data, error } = await this.client.rpc("steno_search", {
|
|
25155
|
-
query_embedding: `[${options.embedding.join(",")}]`,
|
|
25156
|
-
search_query: options.query,
|
|
25157
|
-
match_tenant_id: options.tenantId,
|
|
25158
|
-
match_scope: options.scope,
|
|
25159
|
-
match_scope_id: options.scopeId,
|
|
25160
|
-
match_count: options.limit,
|
|
25161
|
-
min_similarity: options.minSimilarity ?? 0
|
|
25162
|
-
});
|
|
25163
|
-
if (error)
|
|
25164
|
-
throwSupabaseError("compoundSearch", error);
|
|
25165
|
-
return (data ?? []).map((row) => ({
|
|
25166
|
-
source: row["source"],
|
|
25167
|
-
fact: toCamelCase(row),
|
|
25168
|
-
relevanceScore: row["relevance_score"]
|
|
25169
|
-
}));
|
|
25170
|
-
}
|
|
25171
|
-
async getEntitiesForTenant(tenantId, options) {
|
|
25172
|
-
const { limit, cursor } = options;
|
|
25173
|
-
let query = this.client.from("entities").select("*").eq("tenant_id", tenantId).order("created_at", { ascending: true }).limit(limit + 1);
|
|
25174
|
-
if (cursor) {
|
|
25175
|
-
query = query.gt("created_at", cursor);
|
|
25176
|
-
}
|
|
25177
|
-
const { data, error } = await query;
|
|
25178
|
-
if (error)
|
|
25179
|
-
throwSupabaseError("getEntitiesForTenant", error);
|
|
25180
|
-
const rows = data ?? [];
|
|
25181
|
-
const hasMore = rows.length > limit;
|
|
25182
|
-
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
25183
|
-
const entities = page.map((row) => toCamelCase(row));
|
|
25184
|
-
const nextCursor = hasMore && page.length > 0 ? page[page.length - 1]["created_at"] : null;
|
|
25185
|
-
return { data: entities, cursor: nextCursor, hasMore };
|
|
25186
|
-
}
|
|
25187
|
-
async getEntitiesForFact(factId) {
|
|
25188
|
-
const { data: junctionRows, error: junctionError } = await this.client.from("fact_entities").select("entity_id").eq("fact_id", factId);
|
|
25189
|
-
if (junctionError)
|
|
25190
|
-
throwSupabaseError("getEntitiesForFact", junctionError);
|
|
25191
|
-
if (!junctionRows || junctionRows.length === 0)
|
|
25192
|
-
return [];
|
|
25193
|
-
const entityIds = junctionRows.map((row) => row["entity_id"]);
|
|
25194
|
-
const { data, error } = await this.client.from("entities").select("*").in("id", entityIds);
|
|
25195
|
-
if (error)
|
|
25196
|
-
throwSupabaseError("getEntitiesForFact", error);
|
|
25197
|
-
return (data ?? []).map((row) => toCamelCase(row));
|
|
25198
|
-
}
|
|
25199
|
-
async getFactsForEntity(tenantId, entityId, options) {
|
|
25200
|
-
const { limit, cursor } = options;
|
|
25201
|
-
let query = this.client.from("fact_entities").select("fact_id, facts!inner(*)").eq("entity_id", entityId).eq("facts.tenant_id", tenantId).order("created_at", { ascending: false, referencedTable: "facts" }).limit(limit + 1);
|
|
25202
|
-
if (cursor) {
|
|
25203
|
-
query = query.lt("facts.created_at", cursor);
|
|
25204
|
-
}
|
|
25205
|
-
const { data, error } = await query;
|
|
25206
|
-
if (error)
|
|
25207
|
-
throwSupabaseError("getFactsForEntity", error);
|
|
25208
|
-
const rows = data ?? [];
|
|
25209
|
-
const hasMore = rows.length > limit;
|
|
25210
|
-
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
25211
|
-
const facts = page.map((row) => {
|
|
25212
|
-
const factRow = row["facts"];
|
|
25213
|
-
return toCamelCase(factRow);
|
|
25214
|
-
});
|
|
25215
|
-
const nextCursor = hasMore && page.length > 0 ? page[page.length - 1]["facts"]["created_at"] : null;
|
|
25216
|
-
return { data: facts, cursor: nextCursor, hasMore };
|
|
25217
|
-
}
|
|
25218
|
-
async getFactsForEntities(tenantId, entityIds, perEntityLimit) {
|
|
25219
|
-
if (entityIds.length === 0)
|
|
25220
|
-
return [];
|
|
25221
|
-
const { data, error } = await this.client.rpc("get_facts_for_entities", {
|
|
25222
|
-
match_tenant_id: tenantId,
|
|
25223
|
-
entity_ids: entityIds,
|
|
25224
|
-
per_entity_limit: perEntityLimit
|
|
25225
|
-
});
|
|
25226
|
-
if (error)
|
|
25227
|
-
throwSupabaseError("getFactsForEntities", error);
|
|
25228
|
-
return (data ?? []).map((row) => {
|
|
25229
|
-
const entityId = row["entity_id"];
|
|
25230
|
-
const factRow = { ...row };
|
|
25231
|
-
delete factRow["entity_id"];
|
|
25232
|
-
factRow["id"] = factRow["fact_id"];
|
|
25233
|
-
delete factRow["fact_id"];
|
|
25234
|
-
return {
|
|
25235
|
-
entityId,
|
|
25236
|
-
fact: toCamelCase(factRow)
|
|
25237
|
-
};
|
|
25238
|
-
});
|
|
25239
|
-
}
|
|
25240
|
-
async getEdgesForEntity(tenantId, entityId) {
|
|
25241
|
-
const { data, error } = await this.client.from("edges").select("*").eq("tenant_id", tenantId).or(`source_id.eq.${entityId},target_id.eq.${entityId}`);
|
|
25242
|
-
if (error)
|
|
25243
|
-
throwSupabaseError("getEdgesForEntity", error);
|
|
25244
|
-
return (data ?? []).map((row) => toCamelCase(row));
|
|
25245
|
-
}
|
|
25246
|
-
async graphTraversal(options) {
|
|
25247
|
-
const { data, error } = await this.client.rpc("graph_traverse", {
|
|
25248
|
-
match_tenant_id: options.tenantId,
|
|
25249
|
-
seed_entity_ids: options.entityIds,
|
|
25250
|
-
max_depth: options.maxDepth,
|
|
25251
|
-
max_entities: options.maxEntities,
|
|
25252
|
-
match_as_of: options.asOf?.toISOString() ?? null
|
|
25253
|
-
});
|
|
25254
|
-
if (error)
|
|
25255
|
-
throwSupabaseError("graphTraversal", error);
|
|
25256
|
-
const rows = data ?? [];
|
|
25257
|
-
const entityMap = /* @__PURE__ */ new Map();
|
|
25258
|
-
const edgeMap = /* @__PURE__ */ new Map();
|
|
25259
|
-
for (const row of rows) {
|
|
25260
|
-
const entityId = row["entity_id"];
|
|
25261
|
-
if (!entityMap.has(entityId)) {
|
|
25262
|
-
entityMap.set(entityId, {
|
|
25263
|
-
id: entityId,
|
|
25264
|
-
tenantId: options.tenantId,
|
|
25265
|
-
name: row["entity_name"],
|
|
25266
|
-
entityType: row["entity_type"],
|
|
25267
|
-
canonicalName: row["canonical_name"],
|
|
25268
|
-
properties: row["properties"] ?? {},
|
|
25269
|
-
embeddingModel: null,
|
|
25270
|
-
embeddingDim: null,
|
|
25271
|
-
mergeTargetId: null,
|
|
25272
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
25273
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
25274
|
-
});
|
|
25275
|
-
}
|
|
25276
|
-
const edgeId = row["edge_id"];
|
|
25277
|
-
if (edgeId && !edgeMap.has(edgeId)) {
|
|
25278
|
-
edgeMap.set(edgeId, {
|
|
25279
|
-
id: edgeId,
|
|
25280
|
-
tenantId: options.tenantId,
|
|
25281
|
-
sourceId: row["edge_source_id"],
|
|
25282
|
-
targetId: row["edge_target_id"],
|
|
25283
|
-
relation: row["edge_relation"],
|
|
25284
|
-
edgeType: row["edge_type"],
|
|
25285
|
-
weight: row["edge_weight"] ?? 1,
|
|
25286
|
-
validFrom: row["edge_valid_from"] ? new Date(row["edge_valid_from"]) : /* @__PURE__ */ new Date(),
|
|
25287
|
-
validUntil: row["edge_valid_until"] ? new Date(row["edge_valid_until"]) : null,
|
|
25288
|
-
factId: null,
|
|
25289
|
-
confidence: row["edge_confidence"] ?? 1,
|
|
25290
|
-
metadata: {},
|
|
25291
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
25292
|
-
});
|
|
25293
|
-
}
|
|
25294
|
-
}
|
|
25295
|
-
return {
|
|
25296
|
-
entities: Array.from(entityMap.values()),
|
|
25297
|
-
edges: Array.from(edgeMap.values())
|
|
25298
|
-
};
|
|
25299
|
-
}
|
|
25300
|
-
async createTrigger(trigger) {
|
|
25301
|
-
const row = toSnakeCase(trigger);
|
|
25302
|
-
const { data, error } = await this.client.from("triggers").insert(row).select().single();
|
|
25303
|
-
if (error)
|
|
25304
|
-
throwSupabaseError("createTrigger", error);
|
|
25305
|
-
return toCamelCase(data);
|
|
25306
|
-
}
|
|
25307
|
-
async getTrigger(tenantId, id) {
|
|
25308
|
-
const { data, error } = await this.client.from("triggers").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
25309
|
-
if (error)
|
|
25310
|
-
throwSupabaseError("getTrigger", error);
|
|
25311
|
-
if (!data)
|
|
25312
|
-
return null;
|
|
25313
|
-
return toCamelCase(data);
|
|
25314
|
-
}
|
|
25315
|
-
async getActiveTriggers(tenantId, scope, scopeId) {
|
|
25316
|
-
const { data, error } = await this.client.from("triggers").select("*").eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId).eq("active", true).order("priority", { ascending: false });
|
|
25317
|
-
if (error)
|
|
25318
|
-
throwSupabaseError("getActiveTriggers", error);
|
|
25319
|
-
return (data ?? []).map((row) => toCamelCase(row));
|
|
25320
|
-
}
|
|
25321
|
-
async updateTrigger(tenantId, id, updates) {
|
|
25322
|
-
const row = toSnakeCase(updates);
|
|
25323
|
-
const { data, error } = await this.client.from("triggers").update(row).eq("tenant_id", tenantId).eq("id", id).select().single();
|
|
25324
|
-
if (error)
|
|
25325
|
-
throwSupabaseError("updateTrigger", error);
|
|
25326
|
-
return toCamelCase(data);
|
|
25327
|
-
}
|
|
25328
|
-
async deleteTrigger(tenantId, id) {
|
|
25329
|
-
const { error } = await this.client.from("triggers").delete().eq("tenant_id", tenantId).eq("id", id);
|
|
25330
|
-
if (error)
|
|
25331
|
-
throwSupabaseError("deleteTrigger", error);
|
|
25332
|
-
}
|
|
25333
|
-
async incrementTriggerFired(tenantId, id) {
|
|
25334
|
-
const { error } = await this.client.rpc("increment_trigger_fired", {
|
|
25335
|
-
p_tenant_id: tenantId,
|
|
25336
|
-
p_trigger_id: id
|
|
25337
|
-
});
|
|
25338
|
-
if (error)
|
|
25339
|
-
throwSupabaseError("incrementTriggerFired", error);
|
|
25340
|
-
}
|
|
25341
|
-
async createMemoryAccess(access) {
|
|
25342
|
-
const row = toSnakeCase(access);
|
|
25343
|
-
const { data, error } = await this.client.from("memory_accesses").insert(row).select().single();
|
|
25344
|
-
if (error)
|
|
25345
|
-
throwSupabaseError("createMemoryAccess", error);
|
|
25346
|
-
return toCamelCase(data);
|
|
25347
|
-
}
|
|
25348
|
-
async updateFeedback(tenantId, factId, feedback) {
|
|
25349
|
-
const { data: accessRows, error: findError } = await this.client.from("memory_accesses").select("id").eq("tenant_id", tenantId).eq("fact_id", factId).order("accessed_at", { ascending: false }).limit(1);
|
|
25350
|
-
if (findError)
|
|
25351
|
-
throwSupabaseError("updateFeedback", findError);
|
|
25352
|
-
if (!accessRows || accessRows.length === 0)
|
|
25353
|
-
return;
|
|
25354
|
-
const accessId = accessRows[0]["id"];
|
|
25355
|
-
const { error } = await this.client.from("memory_accesses").update({
|
|
25356
|
-
was_useful: feedback.wasUseful,
|
|
25357
|
-
feedback_type: feedback.feedbackType,
|
|
25358
|
-
feedback_detail: feedback.feedbackDetail ?? null,
|
|
25359
|
-
was_corrected: feedback.wasCorrected ?? false
|
|
25360
|
-
}).eq("id", accessId);
|
|
25361
|
-
if (error)
|
|
25362
|
-
throwSupabaseError("updateFeedback", error);
|
|
25363
|
-
}
|
|
25364
|
-
async createSession(session) {
|
|
25365
|
-
const row = toSnakeCase(session);
|
|
25366
|
-
const { data, error } = await this.client.from("sessions").insert(row).select().single();
|
|
25367
|
-
if (error)
|
|
25368
|
-
throwSupabaseError("createSession", error);
|
|
25369
|
-
return toCamelCase(data);
|
|
25370
|
-
}
|
|
25371
|
-
async getSession(tenantId, id) {
|
|
25372
|
-
const { data, error } = await this.client.from("sessions").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
25373
|
-
if (error)
|
|
25374
|
-
throwSupabaseError("getSession", error);
|
|
25375
|
-
if (!data)
|
|
25376
|
-
return null;
|
|
25377
|
-
return toCamelCase(data);
|
|
25378
|
-
}
|
|
25379
|
-
async endSession(tenantId, id, summary, topics) {
|
|
25380
|
-
const updates = {
|
|
25381
|
-
ended_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
25382
|
-
};
|
|
25383
|
-
if (summary !== void 0)
|
|
25384
|
-
updates["summary"] = summary;
|
|
25385
|
-
if (topics !== void 0)
|
|
25386
|
-
updates["topics"] = topics;
|
|
25387
|
-
const { data, error } = await this.client.from("sessions").update(updates).eq("tenant_id", tenantId).eq("id", id).select().single();
|
|
25388
|
-
if (error)
|
|
25389
|
-
throwSupabaseError("endSession", error);
|
|
25390
|
-
return toCamelCase(data);
|
|
25391
|
-
}
|
|
25392
|
-
async getSessionsByScope(tenantId, scope, scopeId, options) {
|
|
25393
|
-
const { limit, cursor } = options;
|
|
25394
|
-
let query = this.client.from("sessions").select("*").eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId).order("started_at", { ascending: false }).limit(limit + 1);
|
|
25395
|
-
if (cursor) {
|
|
25396
|
-
query = query.lt("started_at", cursor);
|
|
25397
|
-
}
|
|
25398
|
-
const { data, error } = await query;
|
|
25399
|
-
if (error)
|
|
25400
|
-
throwSupabaseError("getSessionsByScope", error);
|
|
25401
|
-
const rows = data ?? [];
|
|
25402
|
-
const hasMore = rows.length > limit;
|
|
25403
|
-
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
25404
|
-
const sessions = page.map((row) => toCamelCase(row));
|
|
25405
|
-
const nextCursor = hasMore && page.length > 0 ? page[page.length - 1]["started_at"] : null;
|
|
25406
|
-
return { data: sessions, cursor: nextCursor, hasMore };
|
|
25407
|
-
}
|
|
25408
|
-
// ---------------------------------------------------------------------------
|
|
25409
|
-
// Webhooks
|
|
25410
|
-
// ---------------------------------------------------------------------------
|
|
25411
|
-
async createWebhook(webhook) {
|
|
25412
|
-
const { secret: _secret, ...rest } = webhook;
|
|
25413
|
-
const row = toSnakeCase(rest);
|
|
25414
|
-
const { data, error } = await this.client.from("webhooks").insert(row).select().single();
|
|
25415
|
-
if (error)
|
|
25416
|
-
throwSupabaseError("createWebhook", error);
|
|
25417
|
-
return toCamelCase(data);
|
|
25418
|
-
}
|
|
25419
|
-
async getWebhook(tenantId, id) {
|
|
25420
|
-
const { data, error } = await this.client.from("webhooks").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
25421
|
-
if (error)
|
|
25422
|
-
throwSupabaseError("getWebhook", error);
|
|
25423
|
-
if (!data)
|
|
25424
|
-
return null;
|
|
25425
|
-
return toCamelCase(data);
|
|
25426
|
-
}
|
|
25427
|
-
async getWebhooksForTenant(tenantId) {
|
|
25428
|
-
const { data, error } = await this.client.from("webhooks").select("*").eq("tenant_id", tenantId);
|
|
25429
|
-
if (error)
|
|
25430
|
-
throwSupabaseError("getWebhooksForTenant", error);
|
|
25431
|
-
return (data ?? []).map((row) => toCamelCase(row));
|
|
25432
|
-
}
|
|
25433
|
-
async getWebhooksByEvent(tenantId, event) {
|
|
25434
|
-
const { data, error } = await this.client.from("webhooks").select("*").eq("tenant_id", tenantId).eq("active", true).contains("events", [event]);
|
|
25435
|
-
if (error)
|
|
25436
|
-
throwSupabaseError("getWebhooksByEvent", error);
|
|
25437
|
-
return (data ?? []).map((row) => toCamelCase(row));
|
|
25438
|
-
}
|
|
25439
|
-
async deleteWebhook(tenantId, id) {
|
|
25440
|
-
const { error } = await this.client.from("webhooks").delete().eq("tenant_id", tenantId).eq("id", id);
|
|
25441
|
-
if (error)
|
|
25442
|
-
throwSupabaseError("deleteWebhook", error);
|
|
25443
|
-
}
|
|
25444
|
-
};
|
|
25445
|
-
}
|
|
25446
|
-
});
|
|
25447
|
-
|
|
25448
|
-
// packages/supabase-adapter/src/client.js
|
|
25449
|
-
import { createClient } from "@supabase/supabase-js";
|
|
25450
|
-
function createSupabaseClient(config) {
|
|
25451
|
-
return createClient(config.url, config.serviceRoleKey, {
|
|
25452
|
-
auth: { persistSession: false },
|
|
25453
|
-
db: { schema: "public" }
|
|
25454
|
-
});
|
|
25455
|
-
}
|
|
25456
|
-
var init_client = __esm({
|
|
25457
|
-
"packages/supabase-adapter/src/client.js"() {
|
|
25458
|
-
"use strict";
|
|
25459
|
-
}
|
|
25460
|
-
});
|
|
25461
|
-
|
|
25462
|
-
// packages/supabase-adapter/src/index.js
|
|
25463
|
-
var src_exports = {};
|
|
25464
|
-
__export(src_exports, {
|
|
25465
|
-
SupabaseStorageAdapter: () => SupabaseStorageAdapter,
|
|
25466
|
-
createSupabaseClient: () => createSupabaseClient
|
|
25467
|
-
});
|
|
25468
|
-
var init_src3 = __esm({
|
|
25469
|
-
"packages/supabase-adapter/src/index.js"() {
|
|
25470
|
-
"use strict";
|
|
25471
|
-
init_storage();
|
|
25472
|
-
init_client();
|
|
25473
|
-
}
|
|
25474
|
-
});
|
|
25475
|
-
|
|
25476
|
-
// packages/openai-adapter/src/llm.js
|
|
25477
|
-
import OpenAI from "openai";
|
|
25478
|
-
var OpenAILLMAdapter;
|
|
25479
|
-
var init_llm = __esm({
|
|
25480
|
-
"packages/openai-adapter/src/llm.js"() {
|
|
25481
|
-
"use strict";
|
|
25482
|
-
OpenAILLMAdapter = class {
|
|
25483
|
-
client;
|
|
25484
|
-
model;
|
|
25485
|
-
constructor(config) {
|
|
25486
|
-
this.client = config._client ?? new OpenAI({ apiKey: config.apiKey });
|
|
25487
|
-
this.model = config.model ?? "gpt-4.1-nano";
|
|
25488
|
-
}
|
|
25489
|
-
async complete(messages, options) {
|
|
25490
|
-
const response = await this.client.chat.completions.create({
|
|
25491
|
-
model: this.model,
|
|
25492
|
-
messages,
|
|
25493
|
-
temperature: options?.temperature ?? 0,
|
|
25494
|
-
max_tokens: options?.maxTokens,
|
|
25495
|
-
...options?.responseFormat === "json" ? { response_format: { type: "json_object" } } : {}
|
|
25496
|
-
});
|
|
25497
|
-
const choice = response.choices[0];
|
|
25498
|
-
if (!choice?.message?.content) {
|
|
25499
|
-
throw new Error("OpenAI returned empty response");
|
|
25500
|
-
}
|
|
25501
|
-
return {
|
|
25502
|
-
content: choice.message.content,
|
|
25503
|
-
tokensInput: response.usage?.prompt_tokens ?? 0,
|
|
25504
|
-
tokensOutput: response.usage?.completion_tokens ?? 0,
|
|
25505
|
-
model: response.model
|
|
25506
|
-
};
|
|
25507
|
-
}
|
|
25508
|
-
};
|
|
25509
|
-
}
|
|
25510
|
-
});
|
|
25511
|
-
|
|
25512
|
-
// packages/openai-adapter/src/embedding.js
|
|
25513
|
-
import OpenAI2 from "openai";
|
|
25514
|
-
var OpenAIEmbeddingAdapter;
|
|
25515
|
-
var init_embedding = __esm({
|
|
25516
|
-
"packages/openai-adapter/src/embedding.js"() {
|
|
25517
|
-
"use strict";
|
|
25518
|
-
OpenAIEmbeddingAdapter = class {
|
|
25519
|
-
client;
|
|
25520
|
-
model;
|
|
25521
|
-
dimensions;
|
|
25522
|
-
constructor(config) {
|
|
25523
|
-
this.client = config._client ?? new OpenAI2({ apiKey: config.apiKey });
|
|
25524
|
-
this.model = config.model ?? "text-embedding-3-small";
|
|
25525
|
-
this.dimensions = config.dimensions ?? 1536;
|
|
25526
|
-
}
|
|
25527
|
-
async embed(text) {
|
|
25528
|
-
const response = await this.client.embeddings.create({
|
|
25529
|
-
model: this.model,
|
|
25530
|
-
input: text,
|
|
25531
|
-
dimensions: this.dimensions
|
|
25532
|
-
});
|
|
25533
|
-
const item = response.data[0];
|
|
25534
|
-
if (!item)
|
|
25535
|
-
throw new Error("OpenAI returned empty embedding response");
|
|
25536
|
-
return item.embedding;
|
|
25537
|
-
}
|
|
25538
|
-
async embedBatch(texts) {
|
|
25539
|
-
if (texts.length === 0)
|
|
25540
|
-
return [];
|
|
25541
|
-
const response = await this.client.embeddings.create({
|
|
25542
|
-
model: this.model,
|
|
25543
|
-
input: texts,
|
|
25544
|
-
dimensions: this.dimensions
|
|
25545
|
-
});
|
|
25546
|
-
return response.data.map((d2) => d2.embedding);
|
|
25547
|
-
}
|
|
25548
|
-
};
|
|
25549
|
-
}
|
|
25550
|
-
});
|
|
25551
|
-
|
|
25552
|
-
// packages/openai-adapter/src/index.js
|
|
25553
|
-
var src_exports2 = {};
|
|
25554
|
-
__export(src_exports2, {
|
|
25555
|
-
OpenAIEmbeddingAdapter: () => OpenAIEmbeddingAdapter,
|
|
25556
|
-
OpenAILLMAdapter: () => OpenAILLMAdapter
|
|
25557
|
-
});
|
|
25558
|
-
var init_src4 = __esm({
|
|
25559
|
-
"packages/openai-adapter/src/index.js"() {
|
|
25560
|
-
"use strict";
|
|
25561
|
-
init_llm();
|
|
25562
|
-
init_embedding();
|
|
25563
|
-
}
|
|
25564
|
-
});
|
|
25565
|
-
|
|
25566
|
-
// packages/engine/src/adapters/perplexity-embedding.js
|
|
25567
|
-
var perplexity_embedding_exports = {};
|
|
25568
|
-
__export(perplexity_embedding_exports, {
|
|
25569
|
-
PerplexityEmbeddingAdapter: () => PerplexityEmbeddingAdapter
|
|
25570
|
-
});
|
|
25571
|
-
function decodeAndNormalize(b64String) {
|
|
25572
|
-
const binaryStr = atob(b64String);
|
|
25573
|
-
const bytes = new Uint8Array(binaryStr.length);
|
|
25574
|
-
for (let i3 = 0; i3 < binaryStr.length; i3++) {
|
|
25575
|
-
bytes[i3] = binaryStr.charCodeAt(i3);
|
|
25576
|
-
}
|
|
25577
|
-
const int8 = new Int8Array(bytes.buffer);
|
|
25578
|
-
const float32 = new Array(int8.length);
|
|
25579
|
-
let norm = 0;
|
|
25580
|
-
for (let i3 = 0; i3 < int8.length; i3++) {
|
|
25581
|
-
float32[i3] = int8[i3];
|
|
25582
|
-
norm += float32[i3] * float32[i3];
|
|
25583
|
-
}
|
|
25584
|
-
norm = Math.sqrt(norm);
|
|
25585
|
-
if (norm > 0) {
|
|
25586
|
-
for (let i3 = 0; i3 < float32.length; i3++) {
|
|
25587
|
-
float32[i3] = float32[i3] / norm;
|
|
25588
|
-
}
|
|
25589
|
-
}
|
|
25590
|
-
return float32;
|
|
25591
|
-
}
|
|
25592
|
-
var PerplexityEmbeddingAdapter;
|
|
25593
|
-
var init_perplexity_embedding = __esm({
|
|
25594
|
-
"packages/engine/src/adapters/perplexity-embedding.js"() {
|
|
25595
|
-
"use strict";
|
|
25596
|
-
PerplexityEmbeddingAdapter = class {
|
|
25597
|
-
model;
|
|
25598
|
-
dimensions;
|
|
25599
|
-
apiKey;
|
|
25600
|
-
baseUrl = "https://api.perplexity.ai/v1/embeddings";
|
|
25601
|
-
constructor(config) {
|
|
25602
|
-
this.apiKey = config.apiKey;
|
|
25603
|
-
this.model = config.model ?? "pplx-embed-v1-4b";
|
|
25604
|
-
this.dimensions = config.dimensions ?? 2e3;
|
|
25605
|
-
}
|
|
25606
|
-
async embed(text) {
|
|
25607
|
-
const results = await this.embedBatch([text]);
|
|
25608
|
-
return results[0];
|
|
25609
|
-
}
|
|
25610
|
-
async embedBatch(texts) {
|
|
25611
|
-
if (texts.length === 0)
|
|
25612
|
-
return [];
|
|
25613
|
-
const response = await fetch(this.baseUrl, {
|
|
25614
|
-
method: "POST",
|
|
25615
|
-
headers: {
|
|
25616
|
-
"Authorization": `Bearer ${this.apiKey}`,
|
|
25617
|
-
"Content-Type": "application/json"
|
|
25618
|
-
},
|
|
25619
|
-
body: JSON.stringify({
|
|
25620
|
-
input: texts,
|
|
25621
|
-
model: this.model,
|
|
25622
|
-
...this.dimensions !== 2560 ? { dimensions: this.dimensions } : {}
|
|
25623
|
-
})
|
|
25624
|
-
});
|
|
25625
|
-
if (!response.ok) {
|
|
25626
|
-
const error = await response.text();
|
|
25627
|
-
throw new Error(`Perplexity embedding failed (${response.status}): ${error}`);
|
|
25628
|
-
}
|
|
25629
|
-
const data = await response.json();
|
|
25630
|
-
const sorted = data.data.sort((a2, b) => a2.index - b.index);
|
|
25631
|
-
return sorted.map((d2) => decodeAndNormalize(d2.embedding));
|
|
25632
|
-
}
|
|
25633
|
-
};
|
|
25634
|
-
}
|
|
25635
|
-
});
|
|
25636
|
-
|
|
25637
24756
|
// packages/mcp-server/src/cli.ts
|
|
25638
24757
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
25639
24758
|
|
|
@@ -25933,6 +25052,826 @@ ${text}`
|
|
|
25933
25052
|
return server;
|
|
25934
25053
|
}
|
|
25935
25054
|
|
|
25055
|
+
// packages/supabase-adapter/src/storage.js
|
|
25056
|
+
function camelToSnake(key) {
|
|
25057
|
+
return key.replace(/([A-Z])/g, (match2) => `_${match2.toLowerCase()}`);
|
|
25058
|
+
}
|
|
25059
|
+
function snakeToCamel(key) {
|
|
25060
|
+
return key.replace(/_([a-z])/g, (_2, char) => char.toUpperCase());
|
|
25061
|
+
}
|
|
25062
|
+
function toSnakeCase(obj) {
|
|
25063
|
+
const result = {};
|
|
25064
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
25065
|
+
result[camelToSnake(key)] = value;
|
|
25066
|
+
}
|
|
25067
|
+
return result;
|
|
25068
|
+
}
|
|
25069
|
+
function toCamelCase(obj) {
|
|
25070
|
+
const result = {};
|
|
25071
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
25072
|
+
result[snakeToCamel(key)] = value;
|
|
25073
|
+
}
|
|
25074
|
+
return result;
|
|
25075
|
+
}
|
|
25076
|
+
function throwSupabaseError(method, error) {
|
|
25077
|
+
throw new Error(`SupabaseStorageAdapter.${method}() failed: ${error?.message ?? "unknown error"}`);
|
|
25078
|
+
}
|
|
25079
|
+
var SupabaseStorageAdapter = class {
|
|
25080
|
+
client;
|
|
25081
|
+
constructor(client) {
|
|
25082
|
+
this.client = client;
|
|
25083
|
+
}
|
|
25084
|
+
async ping() {
|
|
25085
|
+
const { error } = await this.client.from("tenants").select("id").limit(1);
|
|
25086
|
+
return !error;
|
|
25087
|
+
}
|
|
25088
|
+
// ---------------------------------------------------------------------------
|
|
25089
|
+
// Tenants
|
|
25090
|
+
// ---------------------------------------------------------------------------
|
|
25091
|
+
async createTenant(tenant) {
|
|
25092
|
+
const row = toSnakeCase(tenant);
|
|
25093
|
+
const { data, error } = await this.client.from("tenants").insert(row).select().single();
|
|
25094
|
+
if (error)
|
|
25095
|
+
throwSupabaseError("createTenant", error);
|
|
25096
|
+
return toCamelCase(data);
|
|
25097
|
+
}
|
|
25098
|
+
async getTenant(id) {
|
|
25099
|
+
const { data, error } = await this.client.from("tenants").select("*").eq("id", id).maybeSingle();
|
|
25100
|
+
if (error)
|
|
25101
|
+
throwSupabaseError("getTenant", error);
|
|
25102
|
+
if (!data)
|
|
25103
|
+
return null;
|
|
25104
|
+
return toCamelCase(data);
|
|
25105
|
+
}
|
|
25106
|
+
async getTenantBySlug(slug) {
|
|
25107
|
+
const { data, error } = await this.client.from("tenants").select("*").eq("slug", slug).maybeSingle();
|
|
25108
|
+
if (error)
|
|
25109
|
+
throwSupabaseError("getTenantBySlug", error);
|
|
25110
|
+
if (!data)
|
|
25111
|
+
return null;
|
|
25112
|
+
return toCamelCase(data);
|
|
25113
|
+
}
|
|
25114
|
+
async updateTenant(id, updates) {
|
|
25115
|
+
const row = toSnakeCase(updates);
|
|
25116
|
+
const { data, error } = await this.client.from("tenants").update(row).eq("id", id).select().single();
|
|
25117
|
+
if (error)
|
|
25118
|
+
throwSupabaseError("updateTenant", error);
|
|
25119
|
+
return toCamelCase(data);
|
|
25120
|
+
}
|
|
25121
|
+
// ---------------------------------------------------------------------------
|
|
25122
|
+
// API Keys
|
|
25123
|
+
// ---------------------------------------------------------------------------
|
|
25124
|
+
async createApiKey(apiKey) {
|
|
25125
|
+
const row = toSnakeCase(apiKey);
|
|
25126
|
+
const { data, error } = await this.client.from("api_keys").insert(row).select().single();
|
|
25127
|
+
if (error)
|
|
25128
|
+
throwSupabaseError("createApiKey", error);
|
|
25129
|
+
return toCamelCase(data);
|
|
25130
|
+
}
|
|
25131
|
+
async getApiKeyByPrefix(prefix5) {
|
|
25132
|
+
const { data, error } = await this.client.from("api_keys").select("*").eq("key_prefix", prefix5).eq("active", true).maybeSingle();
|
|
25133
|
+
if (error)
|
|
25134
|
+
throwSupabaseError("getApiKeyByPrefix", error);
|
|
25135
|
+
if (!data)
|
|
25136
|
+
return null;
|
|
25137
|
+
return toCamelCase(data);
|
|
25138
|
+
}
|
|
25139
|
+
async getApiKeysForTenant(tenantId) {
|
|
25140
|
+
const { data, error } = await this.client.from("api_keys").select("*").eq("tenant_id", tenantId);
|
|
25141
|
+
if (error)
|
|
25142
|
+
throwSupabaseError("getApiKeysForTenant", error);
|
|
25143
|
+
return (data ?? []).map((row) => toCamelCase(row));
|
|
25144
|
+
}
|
|
25145
|
+
async revokeApiKey(tenantId, id) {
|
|
25146
|
+
const { error } = await this.client.from("api_keys").update({ active: false }).eq("id", id).eq("tenant_id", tenantId);
|
|
25147
|
+
if (error)
|
|
25148
|
+
throwSupabaseError("revokeApiKey", error);
|
|
25149
|
+
}
|
|
25150
|
+
async updateApiKeyLastUsed(id) {
|
|
25151
|
+
const { error } = await this.client.from("api_keys").update({ last_used_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", id);
|
|
25152
|
+
if (error)
|
|
25153
|
+
throwSupabaseError("updateApiKeyLastUsed", error);
|
|
25154
|
+
}
|
|
25155
|
+
// ---------------------------------------------------------------------------
|
|
25156
|
+
// Extractions
|
|
25157
|
+
// ---------------------------------------------------------------------------
|
|
25158
|
+
async createExtraction(extraction) {
|
|
25159
|
+
const row = toSnakeCase({
|
|
25160
|
+
...extraction,
|
|
25161
|
+
status: "queued"
|
|
25162
|
+
});
|
|
25163
|
+
const { data, error } = await this.client.from("extractions").insert(row).select().single();
|
|
25164
|
+
if (error)
|
|
25165
|
+
throwSupabaseError("createExtraction", error);
|
|
25166
|
+
return toCamelCase(data);
|
|
25167
|
+
}
|
|
25168
|
+
async getExtraction(tenantId, id) {
|
|
25169
|
+
const { data, error } = await this.client.from("extractions").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
25170
|
+
if (error)
|
|
25171
|
+
throwSupabaseError("getExtraction", error);
|
|
25172
|
+
if (!data)
|
|
25173
|
+
return null;
|
|
25174
|
+
return toCamelCase(data);
|
|
25175
|
+
}
|
|
25176
|
+
async updateExtraction(tenantId, id, updates) {
|
|
25177
|
+
const row = toSnakeCase(updates);
|
|
25178
|
+
const { data, error } = await this.client.from("extractions").update(row).eq("tenant_id", tenantId).eq("id", id).select().single();
|
|
25179
|
+
if (error)
|
|
25180
|
+
throwSupabaseError("updateExtraction", error);
|
|
25181
|
+
return toCamelCase(data);
|
|
25182
|
+
}
|
|
25183
|
+
async getExtractionByHash(tenantId, inputHash) {
|
|
25184
|
+
const { data, error } = await this.client.from("extractions").select("*").eq("tenant_id", tenantId).eq("input_hash", inputHash).maybeSingle();
|
|
25185
|
+
if (error)
|
|
25186
|
+
throwSupabaseError("getExtractionByHash", error);
|
|
25187
|
+
if (!data)
|
|
25188
|
+
return null;
|
|
25189
|
+
return toCamelCase(data);
|
|
25190
|
+
}
|
|
25191
|
+
async getExtractionsByTenant(tenantId, options) {
|
|
25192
|
+
const { limit, cursor } = options;
|
|
25193
|
+
let query = this.client.from("extractions").select("*").eq("tenant_id", tenantId).order("created_at", { ascending: false }).limit(limit + 1);
|
|
25194
|
+
if (cursor) {
|
|
25195
|
+
query = query.lt("created_at", cursor);
|
|
25196
|
+
}
|
|
25197
|
+
const { data, error } = await query;
|
|
25198
|
+
if (error)
|
|
25199
|
+
throwSupabaseError("getExtractionsByTenant", error);
|
|
25200
|
+
const rows = data ?? [];
|
|
25201
|
+
const hasMore = rows.length > limit;
|
|
25202
|
+
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
25203
|
+
const extractions = page.map((row) => toCamelCase(row));
|
|
25204
|
+
const nextCursor = hasMore && page.length > 0 ? page[page.length - 1]["created_at"] : null;
|
|
25205
|
+
return { data: extractions, cursor: nextCursor, hasMore };
|
|
25206
|
+
}
|
|
25207
|
+
// ---------------------------------------------------------------------------
|
|
25208
|
+
// Facts
|
|
25209
|
+
// ---------------------------------------------------------------------------
|
|
25210
|
+
async createFact(fact) {
|
|
25211
|
+
const { embedding, ...rest } = fact;
|
|
25212
|
+
const row = toSnakeCase(rest);
|
|
25213
|
+
if (!("version" in row)) {
|
|
25214
|
+
row["version"] = 1;
|
|
25215
|
+
}
|
|
25216
|
+
if (!row["lineage_id"]) {
|
|
25217
|
+
row["lineage_id"] = fact.id;
|
|
25218
|
+
}
|
|
25219
|
+
if (embedding !== void 0) {
|
|
25220
|
+
row["embedding"] = `[${embedding.join(",")}]`;
|
|
25221
|
+
}
|
|
25222
|
+
const { data, error } = await this.client.from("facts").insert(row).select().single();
|
|
25223
|
+
if (error)
|
|
25224
|
+
throwSupabaseError("createFact", error);
|
|
25225
|
+
return toCamelCase(data);
|
|
25226
|
+
}
|
|
25227
|
+
async getFact(tenantId, id) {
|
|
25228
|
+
const { data, error } = await this.client.from("facts").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
25229
|
+
if (error)
|
|
25230
|
+
throwSupabaseError("getFact", error);
|
|
25231
|
+
if (!data)
|
|
25232
|
+
return null;
|
|
25233
|
+
return toCamelCase(data);
|
|
25234
|
+
}
|
|
25235
|
+
async getFactsByIds(tenantId, ids) {
|
|
25236
|
+
if (ids.length === 0)
|
|
25237
|
+
return [];
|
|
25238
|
+
const { data, error } = await this.client.from("facts").select("*").eq("tenant_id", tenantId).in("id", ids);
|
|
25239
|
+
if (error)
|
|
25240
|
+
throwSupabaseError("getFactsByIds", error);
|
|
25241
|
+
return (data ?? []).map((row) => toCamelCase(row));
|
|
25242
|
+
}
|
|
25243
|
+
async getFactsByLineage(tenantId, lineageId) {
|
|
25244
|
+
const { data, error } = await this.client.from("facts").select("*").eq("tenant_id", tenantId).eq("lineage_id", lineageId).order("version", { ascending: true });
|
|
25245
|
+
if (error)
|
|
25246
|
+
throwSupabaseError("getFactsByLineage", error);
|
|
25247
|
+
return (data ?? []).map((row) => toCamelCase(row));
|
|
25248
|
+
}
|
|
25249
|
+
async invalidateFact(tenantId, id) {
|
|
25250
|
+
const { error } = await this.client.from("facts").update({ valid_until: (/* @__PURE__ */ new Date()).toISOString() }).eq("tenant_id", tenantId).eq("id", id);
|
|
25251
|
+
if (error)
|
|
25252
|
+
throwSupabaseError("invalidateFact", error);
|
|
25253
|
+
}
|
|
25254
|
+
// ---------------------------------------------------------------------------
|
|
25255
|
+
// Entities
|
|
25256
|
+
// ---------------------------------------------------------------------------
|
|
25257
|
+
async createEntity(entity2) {
|
|
25258
|
+
const { embedding, ...rest } = entity2;
|
|
25259
|
+
const row = toSnakeCase(rest);
|
|
25260
|
+
if (embedding !== void 0) {
|
|
25261
|
+
row["embedding"] = `[${embedding.join(",")}]`;
|
|
25262
|
+
}
|
|
25263
|
+
const { data, error } = await this.client.from("entities").insert(row).select().single();
|
|
25264
|
+
if (error)
|
|
25265
|
+
throwSupabaseError("createEntity", error);
|
|
25266
|
+
return toCamelCase(data);
|
|
25267
|
+
}
|
|
25268
|
+
async getEntity(tenantId, id) {
|
|
25269
|
+
const { data, error } = await this.client.from("entities").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
25270
|
+
if (error)
|
|
25271
|
+
throwSupabaseError("getEntity", error);
|
|
25272
|
+
if (!data)
|
|
25273
|
+
return null;
|
|
25274
|
+
return toCamelCase(data);
|
|
25275
|
+
}
|
|
25276
|
+
async findEntityByCanonicalName(tenantId, canonicalName, entityType) {
|
|
25277
|
+
const { data, error } = await this.client.from("entities").select("*").eq("tenant_id", tenantId).eq("canonical_name", canonicalName).eq("entity_type", entityType).maybeSingle();
|
|
25278
|
+
if (error)
|
|
25279
|
+
throwSupabaseError("findEntityByCanonicalName", error);
|
|
25280
|
+
if (!data)
|
|
25281
|
+
return null;
|
|
25282
|
+
return toCamelCase(data);
|
|
25283
|
+
}
|
|
25284
|
+
async findEntitiesByEmbedding(tenantId, embedding, limit, minSimilarity = 0.3) {
|
|
25285
|
+
const { data, error } = await this.client.rpc("match_entities", {
|
|
25286
|
+
query_embedding: JSON.stringify(embedding),
|
|
25287
|
+
match_tenant_id: tenantId,
|
|
25288
|
+
match_count: limit,
|
|
25289
|
+
min_similarity: minSimilarity
|
|
25290
|
+
});
|
|
25291
|
+
if (error)
|
|
25292
|
+
throwSupabaseError("findEntitiesByEmbedding", error);
|
|
25293
|
+
return (data ?? []).map((row) => ({
|
|
25294
|
+
entity: toCamelCase(row),
|
|
25295
|
+
similarity: row["similarity"]
|
|
25296
|
+
}));
|
|
25297
|
+
}
|
|
25298
|
+
// ---------------------------------------------------------------------------
|
|
25299
|
+
// Fact-Entity junction
|
|
25300
|
+
// ---------------------------------------------------------------------------
|
|
25301
|
+
async linkFactEntity(factId, entityId, role) {
|
|
25302
|
+
const { error } = await this.client.from("fact_entities").insert({
|
|
25303
|
+
fact_id: factId,
|
|
25304
|
+
entity_id: entityId,
|
|
25305
|
+
role
|
|
25306
|
+
});
|
|
25307
|
+
if (error)
|
|
25308
|
+
throwSupabaseError("linkFactEntity", error);
|
|
25309
|
+
}
|
|
25310
|
+
// ---------------------------------------------------------------------------
|
|
25311
|
+
// Edges
|
|
25312
|
+
// ---------------------------------------------------------------------------
|
|
25313
|
+
async createEdge(edge) {
|
|
25314
|
+
const row = toSnakeCase(edge);
|
|
25315
|
+
const { data, error } = await this.client.from("edges").insert(row).select().single();
|
|
25316
|
+
if (error)
|
|
25317
|
+
throwSupabaseError("createEdge", error);
|
|
25318
|
+
return toCamelCase(data);
|
|
25319
|
+
}
|
|
25320
|
+
// ---------------------------------------------------------------------------
|
|
25321
|
+
// Vector search
|
|
25322
|
+
// ---------------------------------------------------------------------------
|
|
25323
|
+
async vectorSearch(options) {
|
|
25324
|
+
const { embedding, tenantId, scope, scopeId, limit, minSimilarity } = options;
|
|
25325
|
+
const { data, error } = await this.client.rpc("match_facts", {
|
|
25326
|
+
query_embedding: `[${embedding.join(",")}]`,
|
|
25327
|
+
match_tenant_id: tenantId,
|
|
25328
|
+
match_scope: scope,
|
|
25329
|
+
match_scope_id: scopeId,
|
|
25330
|
+
match_count: limit,
|
|
25331
|
+
min_similarity: minSimilarity ?? 0,
|
|
25332
|
+
match_as_of: options.asOf?.toISOString() ?? null
|
|
25333
|
+
});
|
|
25334
|
+
if (error)
|
|
25335
|
+
throwSupabaseError("vectorSearch", error);
|
|
25336
|
+
return (data ?? []).map((row) => ({
|
|
25337
|
+
fact: toCamelCase(row),
|
|
25338
|
+
similarity: row["similarity"]
|
|
25339
|
+
}));
|
|
25340
|
+
}
|
|
25341
|
+
// ---------------------------------------------------------------------------
|
|
25342
|
+
// Usage
|
|
25343
|
+
// ---------------------------------------------------------------------------
|
|
25344
|
+
async incrementUsage(tenantId, tokens, queries, extractions, costUsd) {
|
|
25345
|
+
const { error } = await this.client.rpc("increment_usage", {
|
|
25346
|
+
p_tenant_id: tenantId,
|
|
25347
|
+
p_tokens: tokens,
|
|
25348
|
+
p_queries: queries,
|
|
25349
|
+
p_extractions: extractions,
|
|
25350
|
+
p_cost_usd: costUsd
|
|
25351
|
+
});
|
|
25352
|
+
if (error)
|
|
25353
|
+
throwSupabaseError("incrementUsage", error);
|
|
25354
|
+
}
|
|
25355
|
+
async getUsage(tenantId, periodStart) {
|
|
25356
|
+
const { data, error } = await this.client.from("usage_records").select("*").eq("tenant_id", tenantId).eq("period_start", periodStart.toISOString()).maybeSingle();
|
|
25357
|
+
if (error)
|
|
25358
|
+
throwSupabaseError("getUsage", error);
|
|
25359
|
+
if (!data)
|
|
25360
|
+
return null;
|
|
25361
|
+
return toCamelCase(data);
|
|
25362
|
+
}
|
|
25363
|
+
async getCurrentUsage(tenantId) {
|
|
25364
|
+
const now = /* @__PURE__ */ new Date();
|
|
25365
|
+
const periodStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
25366
|
+
return this.getUsage(tenantId, periodStart);
|
|
25367
|
+
}
|
|
25368
|
+
// ---------------------------------------------------------------------------
|
|
25369
|
+
// Stubs — implemented in Plan 3 (Retrieval Engine)
|
|
25370
|
+
// ---------------------------------------------------------------------------
|
|
25371
|
+
async getFactsByScope(tenantId, scope, scopeId, options) {
|
|
25372
|
+
const { limit, cursor } = options;
|
|
25373
|
+
let query = this.client.from("facts").select("*").eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId).order("created_at", { ascending: false }).limit(limit + 1);
|
|
25374
|
+
if (cursor) {
|
|
25375
|
+
query = query.lt("created_at", cursor);
|
|
25376
|
+
}
|
|
25377
|
+
const { data, error } = await query;
|
|
25378
|
+
if (error)
|
|
25379
|
+
throwSupabaseError("getFactsByScope", error);
|
|
25380
|
+
const rows = data ?? [];
|
|
25381
|
+
const hasMore = rows.length > limit;
|
|
25382
|
+
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
25383
|
+
const facts = page.map((row) => toCamelCase(row));
|
|
25384
|
+
const nextCursor = hasMore && page.length > 0 ? page[page.length - 1]["created_at"] : null;
|
|
25385
|
+
return { data: facts, cursor: nextCursor, hasMore };
|
|
25386
|
+
}
|
|
25387
|
+
async purgeFacts(tenantId, scope, scopeId) {
|
|
25388
|
+
const { data: factRows, error: fetchError } = await this.client.from("facts").select("id").eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId);
|
|
25389
|
+
if (fetchError)
|
|
25390
|
+
throwSupabaseError("purgeFacts", fetchError);
|
|
25391
|
+
const factIds = (factRows ?? []).map((row) => row["id"]);
|
|
25392
|
+
if (factIds.length === 0)
|
|
25393
|
+
return 0;
|
|
25394
|
+
const { error: feError } = await this.client.from("fact_entities").delete().in("fact_id", factIds);
|
|
25395
|
+
if (feError)
|
|
25396
|
+
throwSupabaseError("purgeFacts", feError);
|
|
25397
|
+
const { error: edgeError } = await this.client.from("edges").delete().in("fact_id", factIds);
|
|
25398
|
+
if (edgeError)
|
|
25399
|
+
throwSupabaseError("purgeFacts", edgeError);
|
|
25400
|
+
const { error: deleteError } = await this.client.from("facts").delete().eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId);
|
|
25401
|
+
if (deleteError)
|
|
25402
|
+
throwSupabaseError("purgeFacts", deleteError);
|
|
25403
|
+
const { error: extractionError } = await this.client.from("extractions").delete().eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId);
|
|
25404
|
+
if (extractionError)
|
|
25405
|
+
throwSupabaseError("purgeFacts", extractionError);
|
|
25406
|
+
return factIds.length;
|
|
25407
|
+
}
|
|
25408
|
+
async updateDecayScores(tenantId, facts) {
|
|
25409
|
+
for (const fact of facts) {
|
|
25410
|
+
const updates = {
|
|
25411
|
+
decay_score: fact.decayScore
|
|
25412
|
+
};
|
|
25413
|
+
if (fact.lastAccessed !== void 0) {
|
|
25414
|
+
updates["last_accessed"] = fact.lastAccessed.toISOString();
|
|
25415
|
+
}
|
|
25416
|
+
if (fact.frequency !== void 0) {
|
|
25417
|
+
updates["frequency"] = fact.frequency;
|
|
25418
|
+
}
|
|
25419
|
+
if (fact.importance !== void 0) {
|
|
25420
|
+
updates["importance"] = fact.importance;
|
|
25421
|
+
}
|
|
25422
|
+
const { error } = await this.client.from("facts").update(updates).eq("tenant_id", tenantId).eq("id", fact.id);
|
|
25423
|
+
if (error)
|
|
25424
|
+
throwSupabaseError("updateDecayScores", error);
|
|
25425
|
+
}
|
|
25426
|
+
}
|
|
25427
|
+
async keywordSearch(options) {
|
|
25428
|
+
const { query, tenantId, scope, scopeId, limit, asOf } = options;
|
|
25429
|
+
const { data, error } = await this.client.rpc("keyword_search_facts", {
|
|
25430
|
+
search_query: query,
|
|
25431
|
+
match_tenant_id: tenantId,
|
|
25432
|
+
match_scope: scope,
|
|
25433
|
+
match_scope_id: scopeId,
|
|
25434
|
+
match_count: limit,
|
|
25435
|
+
match_as_of: asOf?.toISOString() ?? null
|
|
25436
|
+
});
|
|
25437
|
+
if (error)
|
|
25438
|
+
throwSupabaseError("keywordSearch", error);
|
|
25439
|
+
return (data ?? []).map((row) => {
|
|
25440
|
+
const rankScore = row["rank_score"];
|
|
25441
|
+
const converted = toCamelCase(row);
|
|
25442
|
+
return {
|
|
25443
|
+
fact: converted,
|
|
25444
|
+
rankScore
|
|
25445
|
+
};
|
|
25446
|
+
});
|
|
25447
|
+
}
|
|
25448
|
+
async compoundSearch(options) {
|
|
25449
|
+
const { data, error } = await this.client.rpc("steno_search", {
|
|
25450
|
+
query_embedding: `[${options.embedding.join(",")}]`,
|
|
25451
|
+
search_query: options.query,
|
|
25452
|
+
match_tenant_id: options.tenantId,
|
|
25453
|
+
match_scope: options.scope,
|
|
25454
|
+
match_scope_id: options.scopeId,
|
|
25455
|
+
match_count: options.limit,
|
|
25456
|
+
min_similarity: options.minSimilarity ?? 0
|
|
25457
|
+
});
|
|
25458
|
+
if (error)
|
|
25459
|
+
throwSupabaseError("compoundSearch", error);
|
|
25460
|
+
return (data ?? []).map((row) => ({
|
|
25461
|
+
source: row["source"],
|
|
25462
|
+
fact: toCamelCase(row),
|
|
25463
|
+
relevanceScore: row["relevance_score"]
|
|
25464
|
+
}));
|
|
25465
|
+
}
|
|
25466
|
+
async getEntitiesForTenant(tenantId, options) {
|
|
25467
|
+
const { limit, cursor } = options;
|
|
25468
|
+
let query = this.client.from("entities").select("*").eq("tenant_id", tenantId).order("created_at", { ascending: true }).limit(limit + 1);
|
|
25469
|
+
if (cursor) {
|
|
25470
|
+
query = query.gt("created_at", cursor);
|
|
25471
|
+
}
|
|
25472
|
+
const { data, error } = await query;
|
|
25473
|
+
if (error)
|
|
25474
|
+
throwSupabaseError("getEntitiesForTenant", error);
|
|
25475
|
+
const rows = data ?? [];
|
|
25476
|
+
const hasMore = rows.length > limit;
|
|
25477
|
+
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
25478
|
+
const entities = page.map((row) => toCamelCase(row));
|
|
25479
|
+
const nextCursor = hasMore && page.length > 0 ? page[page.length - 1]["created_at"] : null;
|
|
25480
|
+
return { data: entities, cursor: nextCursor, hasMore };
|
|
25481
|
+
}
|
|
25482
|
+
async getEntitiesForFact(factId) {
|
|
25483
|
+
const { data: junctionRows, error: junctionError } = await this.client.from("fact_entities").select("entity_id").eq("fact_id", factId);
|
|
25484
|
+
if (junctionError)
|
|
25485
|
+
throwSupabaseError("getEntitiesForFact", junctionError);
|
|
25486
|
+
if (!junctionRows || junctionRows.length === 0)
|
|
25487
|
+
return [];
|
|
25488
|
+
const entityIds = junctionRows.map((row) => row["entity_id"]);
|
|
25489
|
+
const { data, error } = await this.client.from("entities").select("*").in("id", entityIds);
|
|
25490
|
+
if (error)
|
|
25491
|
+
throwSupabaseError("getEntitiesForFact", error);
|
|
25492
|
+
return (data ?? []).map((row) => toCamelCase(row));
|
|
25493
|
+
}
|
|
25494
|
+
async getFactsForEntity(tenantId, entityId, options) {
|
|
25495
|
+
const { limit, cursor } = options;
|
|
25496
|
+
let query = this.client.from("fact_entities").select("fact_id, facts!inner(*)").eq("entity_id", entityId).eq("facts.tenant_id", tenantId).order("created_at", { ascending: false, referencedTable: "facts" }).limit(limit + 1);
|
|
25497
|
+
if (cursor) {
|
|
25498
|
+
query = query.lt("facts.created_at", cursor);
|
|
25499
|
+
}
|
|
25500
|
+
const { data, error } = await query;
|
|
25501
|
+
if (error)
|
|
25502
|
+
throwSupabaseError("getFactsForEntity", error);
|
|
25503
|
+
const rows = data ?? [];
|
|
25504
|
+
const hasMore = rows.length > limit;
|
|
25505
|
+
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
25506
|
+
const facts = page.map((row) => {
|
|
25507
|
+
const factRow = row["facts"];
|
|
25508
|
+
return toCamelCase(factRow);
|
|
25509
|
+
});
|
|
25510
|
+
const nextCursor = hasMore && page.length > 0 ? page[page.length - 1]["facts"]["created_at"] : null;
|
|
25511
|
+
return { data: facts, cursor: nextCursor, hasMore };
|
|
25512
|
+
}
|
|
25513
|
+
async getFactsForEntities(tenantId, entityIds, perEntityLimit) {
|
|
25514
|
+
if (entityIds.length === 0)
|
|
25515
|
+
return [];
|
|
25516
|
+
const { data, error } = await this.client.rpc("get_facts_for_entities", {
|
|
25517
|
+
match_tenant_id: tenantId,
|
|
25518
|
+
entity_ids: entityIds,
|
|
25519
|
+
per_entity_limit: perEntityLimit
|
|
25520
|
+
});
|
|
25521
|
+
if (error)
|
|
25522
|
+
throwSupabaseError("getFactsForEntities", error);
|
|
25523
|
+
return (data ?? []).map((row) => {
|
|
25524
|
+
const entityId = row["entity_id"];
|
|
25525
|
+
const factRow = { ...row };
|
|
25526
|
+
delete factRow["entity_id"];
|
|
25527
|
+
factRow["id"] = factRow["fact_id"];
|
|
25528
|
+
delete factRow["fact_id"];
|
|
25529
|
+
return {
|
|
25530
|
+
entityId,
|
|
25531
|
+
fact: toCamelCase(factRow)
|
|
25532
|
+
};
|
|
25533
|
+
});
|
|
25534
|
+
}
|
|
25535
|
+
async getEdgesForEntity(tenantId, entityId) {
|
|
25536
|
+
const { data, error } = await this.client.from("edges").select("*").eq("tenant_id", tenantId).or(`source_id.eq.${entityId},target_id.eq.${entityId}`);
|
|
25537
|
+
if (error)
|
|
25538
|
+
throwSupabaseError("getEdgesForEntity", error);
|
|
25539
|
+
return (data ?? []).map((row) => toCamelCase(row));
|
|
25540
|
+
}
|
|
25541
|
+
async graphTraversal(options) {
|
|
25542
|
+
const { data, error } = await this.client.rpc("graph_traverse", {
|
|
25543
|
+
match_tenant_id: options.tenantId,
|
|
25544
|
+
seed_entity_ids: options.entityIds,
|
|
25545
|
+
max_depth: options.maxDepth,
|
|
25546
|
+
max_entities: options.maxEntities,
|
|
25547
|
+
match_as_of: options.asOf?.toISOString() ?? null
|
|
25548
|
+
});
|
|
25549
|
+
if (error)
|
|
25550
|
+
throwSupabaseError("graphTraversal", error);
|
|
25551
|
+
const rows = data ?? [];
|
|
25552
|
+
const entityMap = /* @__PURE__ */ new Map();
|
|
25553
|
+
const edgeMap = /* @__PURE__ */ new Map();
|
|
25554
|
+
for (const row of rows) {
|
|
25555
|
+
const entityId = row["entity_id"];
|
|
25556
|
+
if (!entityMap.has(entityId)) {
|
|
25557
|
+
entityMap.set(entityId, {
|
|
25558
|
+
id: entityId,
|
|
25559
|
+
tenantId: options.tenantId,
|
|
25560
|
+
name: row["entity_name"],
|
|
25561
|
+
entityType: row["entity_type"],
|
|
25562
|
+
canonicalName: row["canonical_name"],
|
|
25563
|
+
properties: row["properties"] ?? {},
|
|
25564
|
+
embeddingModel: null,
|
|
25565
|
+
embeddingDim: null,
|
|
25566
|
+
mergeTargetId: null,
|
|
25567
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
25568
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
25569
|
+
});
|
|
25570
|
+
}
|
|
25571
|
+
const edgeId = row["edge_id"];
|
|
25572
|
+
if (edgeId && !edgeMap.has(edgeId)) {
|
|
25573
|
+
edgeMap.set(edgeId, {
|
|
25574
|
+
id: edgeId,
|
|
25575
|
+
tenantId: options.tenantId,
|
|
25576
|
+
sourceId: row["edge_source_id"],
|
|
25577
|
+
targetId: row["edge_target_id"],
|
|
25578
|
+
relation: row["edge_relation"],
|
|
25579
|
+
edgeType: row["edge_type"],
|
|
25580
|
+
weight: row["edge_weight"] ?? 1,
|
|
25581
|
+
validFrom: row["edge_valid_from"] ? new Date(row["edge_valid_from"]) : /* @__PURE__ */ new Date(),
|
|
25582
|
+
validUntil: row["edge_valid_until"] ? new Date(row["edge_valid_until"]) : null,
|
|
25583
|
+
factId: null,
|
|
25584
|
+
confidence: row["edge_confidence"] ?? 1,
|
|
25585
|
+
metadata: {},
|
|
25586
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
25587
|
+
});
|
|
25588
|
+
}
|
|
25589
|
+
}
|
|
25590
|
+
return {
|
|
25591
|
+
entities: Array.from(entityMap.values()),
|
|
25592
|
+
edges: Array.from(edgeMap.values())
|
|
25593
|
+
};
|
|
25594
|
+
}
|
|
25595
|
+
async createTrigger(trigger) {
|
|
25596
|
+
const row = toSnakeCase(trigger);
|
|
25597
|
+
const { data, error } = await this.client.from("triggers").insert(row).select().single();
|
|
25598
|
+
if (error)
|
|
25599
|
+
throwSupabaseError("createTrigger", error);
|
|
25600
|
+
return toCamelCase(data);
|
|
25601
|
+
}
|
|
25602
|
+
async getTrigger(tenantId, id) {
|
|
25603
|
+
const { data, error } = await this.client.from("triggers").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
25604
|
+
if (error)
|
|
25605
|
+
throwSupabaseError("getTrigger", error);
|
|
25606
|
+
if (!data)
|
|
25607
|
+
return null;
|
|
25608
|
+
return toCamelCase(data);
|
|
25609
|
+
}
|
|
25610
|
+
async getActiveTriggers(tenantId, scope, scopeId) {
|
|
25611
|
+
const { data, error } = await this.client.from("triggers").select("*").eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId).eq("active", true).order("priority", { ascending: false });
|
|
25612
|
+
if (error)
|
|
25613
|
+
throwSupabaseError("getActiveTriggers", error);
|
|
25614
|
+
return (data ?? []).map((row) => toCamelCase(row));
|
|
25615
|
+
}
|
|
25616
|
+
async updateTrigger(tenantId, id, updates) {
|
|
25617
|
+
const row = toSnakeCase(updates);
|
|
25618
|
+
const { data, error } = await this.client.from("triggers").update(row).eq("tenant_id", tenantId).eq("id", id).select().single();
|
|
25619
|
+
if (error)
|
|
25620
|
+
throwSupabaseError("updateTrigger", error);
|
|
25621
|
+
return toCamelCase(data);
|
|
25622
|
+
}
|
|
25623
|
+
async deleteTrigger(tenantId, id) {
|
|
25624
|
+
const { error } = await this.client.from("triggers").delete().eq("tenant_id", tenantId).eq("id", id);
|
|
25625
|
+
if (error)
|
|
25626
|
+
throwSupabaseError("deleteTrigger", error);
|
|
25627
|
+
}
|
|
25628
|
+
async incrementTriggerFired(tenantId, id) {
|
|
25629
|
+
const { error } = await this.client.rpc("increment_trigger_fired", {
|
|
25630
|
+
p_tenant_id: tenantId,
|
|
25631
|
+
p_trigger_id: id
|
|
25632
|
+
});
|
|
25633
|
+
if (error)
|
|
25634
|
+
throwSupabaseError("incrementTriggerFired", error);
|
|
25635
|
+
}
|
|
25636
|
+
async createMemoryAccess(access) {
|
|
25637
|
+
const row = toSnakeCase(access);
|
|
25638
|
+
const { data, error } = await this.client.from("memory_accesses").insert(row).select().single();
|
|
25639
|
+
if (error)
|
|
25640
|
+
throwSupabaseError("createMemoryAccess", error);
|
|
25641
|
+
return toCamelCase(data);
|
|
25642
|
+
}
|
|
25643
|
+
async updateFeedback(tenantId, factId, feedback) {
|
|
25644
|
+
const { data: accessRows, error: findError } = await this.client.from("memory_accesses").select("id").eq("tenant_id", tenantId).eq("fact_id", factId).order("accessed_at", { ascending: false }).limit(1);
|
|
25645
|
+
if (findError)
|
|
25646
|
+
throwSupabaseError("updateFeedback", findError);
|
|
25647
|
+
if (!accessRows || accessRows.length === 0)
|
|
25648
|
+
return;
|
|
25649
|
+
const accessId = accessRows[0]["id"];
|
|
25650
|
+
const { error } = await this.client.from("memory_accesses").update({
|
|
25651
|
+
was_useful: feedback.wasUseful,
|
|
25652
|
+
feedback_type: feedback.feedbackType,
|
|
25653
|
+
feedback_detail: feedback.feedbackDetail ?? null,
|
|
25654
|
+
was_corrected: feedback.wasCorrected ?? false
|
|
25655
|
+
}).eq("id", accessId);
|
|
25656
|
+
if (error)
|
|
25657
|
+
throwSupabaseError("updateFeedback", error);
|
|
25658
|
+
}
|
|
25659
|
+
async createSession(session) {
|
|
25660
|
+
const row = toSnakeCase(session);
|
|
25661
|
+
const { data, error } = await this.client.from("sessions").insert(row).select().single();
|
|
25662
|
+
if (error)
|
|
25663
|
+
throwSupabaseError("createSession", error);
|
|
25664
|
+
return toCamelCase(data);
|
|
25665
|
+
}
|
|
25666
|
+
async getSession(tenantId, id) {
|
|
25667
|
+
const { data, error } = await this.client.from("sessions").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
25668
|
+
if (error)
|
|
25669
|
+
throwSupabaseError("getSession", error);
|
|
25670
|
+
if (!data)
|
|
25671
|
+
return null;
|
|
25672
|
+
return toCamelCase(data);
|
|
25673
|
+
}
|
|
25674
|
+
async endSession(tenantId, id, summary, topics) {
|
|
25675
|
+
const updates = {
|
|
25676
|
+
ended_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
25677
|
+
};
|
|
25678
|
+
if (summary !== void 0)
|
|
25679
|
+
updates["summary"] = summary;
|
|
25680
|
+
if (topics !== void 0)
|
|
25681
|
+
updates["topics"] = topics;
|
|
25682
|
+
const { data, error } = await this.client.from("sessions").update(updates).eq("tenant_id", tenantId).eq("id", id).select().single();
|
|
25683
|
+
if (error)
|
|
25684
|
+
throwSupabaseError("endSession", error);
|
|
25685
|
+
return toCamelCase(data);
|
|
25686
|
+
}
|
|
25687
|
+
async getSessionsByScope(tenantId, scope, scopeId, options) {
|
|
25688
|
+
const { limit, cursor } = options;
|
|
25689
|
+
let query = this.client.from("sessions").select("*").eq("tenant_id", tenantId).eq("scope", scope).eq("scope_id", scopeId).order("started_at", { ascending: false }).limit(limit + 1);
|
|
25690
|
+
if (cursor) {
|
|
25691
|
+
query = query.lt("started_at", cursor);
|
|
25692
|
+
}
|
|
25693
|
+
const { data, error } = await query;
|
|
25694
|
+
if (error)
|
|
25695
|
+
throwSupabaseError("getSessionsByScope", error);
|
|
25696
|
+
const rows = data ?? [];
|
|
25697
|
+
const hasMore = rows.length > limit;
|
|
25698
|
+
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
25699
|
+
const sessions = page.map((row) => toCamelCase(row));
|
|
25700
|
+
const nextCursor = hasMore && page.length > 0 ? page[page.length - 1]["started_at"] : null;
|
|
25701
|
+
return { data: sessions, cursor: nextCursor, hasMore };
|
|
25702
|
+
}
|
|
25703
|
+
// ---------------------------------------------------------------------------
|
|
25704
|
+
// Webhooks
|
|
25705
|
+
// ---------------------------------------------------------------------------
|
|
25706
|
+
async createWebhook(webhook) {
|
|
25707
|
+
const { secret: _secret, ...rest } = webhook;
|
|
25708
|
+
const row = toSnakeCase(rest);
|
|
25709
|
+
const { data, error } = await this.client.from("webhooks").insert(row).select().single();
|
|
25710
|
+
if (error)
|
|
25711
|
+
throwSupabaseError("createWebhook", error);
|
|
25712
|
+
return toCamelCase(data);
|
|
25713
|
+
}
|
|
25714
|
+
async getWebhook(tenantId, id) {
|
|
25715
|
+
const { data, error } = await this.client.from("webhooks").select("*").eq("tenant_id", tenantId).eq("id", id).maybeSingle();
|
|
25716
|
+
if (error)
|
|
25717
|
+
throwSupabaseError("getWebhook", error);
|
|
25718
|
+
if (!data)
|
|
25719
|
+
return null;
|
|
25720
|
+
return toCamelCase(data);
|
|
25721
|
+
}
|
|
25722
|
+
async getWebhooksForTenant(tenantId) {
|
|
25723
|
+
const { data, error } = await this.client.from("webhooks").select("*").eq("tenant_id", tenantId);
|
|
25724
|
+
if (error)
|
|
25725
|
+
throwSupabaseError("getWebhooksForTenant", error);
|
|
25726
|
+
return (data ?? []).map((row) => toCamelCase(row));
|
|
25727
|
+
}
|
|
25728
|
+
async getWebhooksByEvent(tenantId, event) {
|
|
25729
|
+
const { data, error } = await this.client.from("webhooks").select("*").eq("tenant_id", tenantId).eq("active", true).contains("events", [event]);
|
|
25730
|
+
if (error)
|
|
25731
|
+
throwSupabaseError("getWebhooksByEvent", error);
|
|
25732
|
+
return (data ?? []).map((row) => toCamelCase(row));
|
|
25733
|
+
}
|
|
25734
|
+
async deleteWebhook(tenantId, id) {
|
|
25735
|
+
const { error } = await this.client.from("webhooks").delete().eq("tenant_id", tenantId).eq("id", id);
|
|
25736
|
+
if (error)
|
|
25737
|
+
throwSupabaseError("deleteWebhook", error);
|
|
25738
|
+
}
|
|
25739
|
+
};
|
|
25740
|
+
|
|
25741
|
+
// packages/supabase-adapter/src/client.js
|
|
25742
|
+
import { createClient } from "@supabase/supabase-js";
|
|
25743
|
+
function createSupabaseClient(config) {
|
|
25744
|
+
return createClient(config.url, config.serviceRoleKey, {
|
|
25745
|
+
auth: { persistSession: false },
|
|
25746
|
+
db: { schema: "public" }
|
|
25747
|
+
});
|
|
25748
|
+
}
|
|
25749
|
+
|
|
25750
|
+
// packages/openai-adapter/src/llm.js
|
|
25751
|
+
import OpenAI from "openai";
|
|
25752
|
+
var OpenAILLMAdapter = class {
|
|
25753
|
+
client;
|
|
25754
|
+
model;
|
|
25755
|
+
constructor(config) {
|
|
25756
|
+
this.client = config._client ?? new OpenAI({ apiKey: config.apiKey });
|
|
25757
|
+
this.model = config.model ?? "gpt-4.1-nano";
|
|
25758
|
+
}
|
|
25759
|
+
async complete(messages, options) {
|
|
25760
|
+
const response = await this.client.chat.completions.create({
|
|
25761
|
+
model: this.model,
|
|
25762
|
+
messages,
|
|
25763
|
+
temperature: options?.temperature ?? 0,
|
|
25764
|
+
max_tokens: options?.maxTokens,
|
|
25765
|
+
...options?.responseFormat === "json" ? { response_format: { type: "json_object" } } : {}
|
|
25766
|
+
});
|
|
25767
|
+
const choice = response.choices[0];
|
|
25768
|
+
if (!choice?.message?.content) {
|
|
25769
|
+
throw new Error("OpenAI returned empty response");
|
|
25770
|
+
}
|
|
25771
|
+
return {
|
|
25772
|
+
content: choice.message.content,
|
|
25773
|
+
tokensInput: response.usage?.prompt_tokens ?? 0,
|
|
25774
|
+
tokensOutput: response.usage?.completion_tokens ?? 0,
|
|
25775
|
+
model: response.model
|
|
25776
|
+
};
|
|
25777
|
+
}
|
|
25778
|
+
};
|
|
25779
|
+
|
|
25780
|
+
// packages/openai-adapter/src/embedding.js
|
|
25781
|
+
import OpenAI2 from "openai";
|
|
25782
|
+
var OpenAIEmbeddingAdapter = class {
|
|
25783
|
+
client;
|
|
25784
|
+
model;
|
|
25785
|
+
dimensions;
|
|
25786
|
+
constructor(config) {
|
|
25787
|
+
this.client = config._client ?? new OpenAI2({ apiKey: config.apiKey });
|
|
25788
|
+
this.model = config.model ?? "text-embedding-3-small";
|
|
25789
|
+
this.dimensions = config.dimensions ?? 1536;
|
|
25790
|
+
}
|
|
25791
|
+
async embed(text) {
|
|
25792
|
+
const response = await this.client.embeddings.create({
|
|
25793
|
+
model: this.model,
|
|
25794
|
+
input: text,
|
|
25795
|
+
dimensions: this.dimensions
|
|
25796
|
+
});
|
|
25797
|
+
const item = response.data[0];
|
|
25798
|
+
if (!item)
|
|
25799
|
+
throw new Error("OpenAI returned empty embedding response");
|
|
25800
|
+
return item.embedding;
|
|
25801
|
+
}
|
|
25802
|
+
async embedBatch(texts) {
|
|
25803
|
+
if (texts.length === 0)
|
|
25804
|
+
return [];
|
|
25805
|
+
const response = await this.client.embeddings.create({
|
|
25806
|
+
model: this.model,
|
|
25807
|
+
input: texts,
|
|
25808
|
+
dimensions: this.dimensions
|
|
25809
|
+
});
|
|
25810
|
+
return response.data.map((d2) => d2.embedding);
|
|
25811
|
+
}
|
|
25812
|
+
};
|
|
25813
|
+
|
|
25814
|
+
// packages/engine/src/adapters/perplexity-embedding.js
|
|
25815
|
+
var PerplexityEmbeddingAdapter = class {
|
|
25816
|
+
model;
|
|
25817
|
+
dimensions;
|
|
25818
|
+
apiKey;
|
|
25819
|
+
baseUrl = "https://api.perplexity.ai/v1/embeddings";
|
|
25820
|
+
constructor(config) {
|
|
25821
|
+
this.apiKey = config.apiKey;
|
|
25822
|
+
this.model = config.model ?? "pplx-embed-v1-4b";
|
|
25823
|
+
this.dimensions = config.dimensions ?? 2e3;
|
|
25824
|
+
}
|
|
25825
|
+
async embed(text) {
|
|
25826
|
+
const results = await this.embedBatch([text]);
|
|
25827
|
+
return results[0];
|
|
25828
|
+
}
|
|
25829
|
+
async embedBatch(texts) {
|
|
25830
|
+
if (texts.length === 0)
|
|
25831
|
+
return [];
|
|
25832
|
+
const response = await fetch(this.baseUrl, {
|
|
25833
|
+
method: "POST",
|
|
25834
|
+
headers: {
|
|
25835
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
25836
|
+
"Content-Type": "application/json"
|
|
25837
|
+
},
|
|
25838
|
+
body: JSON.stringify({
|
|
25839
|
+
input: texts,
|
|
25840
|
+
model: this.model,
|
|
25841
|
+
...this.dimensions !== 2560 ? { dimensions: this.dimensions } : {}
|
|
25842
|
+
})
|
|
25843
|
+
});
|
|
25844
|
+
if (!response.ok) {
|
|
25845
|
+
const error = await response.text();
|
|
25846
|
+
throw new Error(`Perplexity embedding failed (${response.status}): ${error}`);
|
|
25847
|
+
}
|
|
25848
|
+
const data = await response.json();
|
|
25849
|
+
const sorted = data.data.sort((a2, b) => a2.index - b.index);
|
|
25850
|
+
return sorted.map((d2) => decodeAndNormalize(d2.embedding));
|
|
25851
|
+
}
|
|
25852
|
+
};
|
|
25853
|
+
function decodeAndNormalize(b64String) {
|
|
25854
|
+
const binaryStr = atob(b64String);
|
|
25855
|
+
const bytes = new Uint8Array(binaryStr.length);
|
|
25856
|
+
for (let i3 = 0; i3 < binaryStr.length; i3++) {
|
|
25857
|
+
bytes[i3] = binaryStr.charCodeAt(i3);
|
|
25858
|
+
}
|
|
25859
|
+
const int8 = new Int8Array(bytes.buffer);
|
|
25860
|
+
const float32 = new Array(int8.length);
|
|
25861
|
+
let norm = 0;
|
|
25862
|
+
for (let i3 = 0; i3 < int8.length; i3++) {
|
|
25863
|
+
float32[i3] = int8[i3];
|
|
25864
|
+
norm += float32[i3] * float32[i3];
|
|
25865
|
+
}
|
|
25866
|
+
norm = Math.sqrt(norm);
|
|
25867
|
+
if (norm > 0) {
|
|
25868
|
+
for (let i3 = 0; i3 < float32.length; i3++) {
|
|
25869
|
+
float32[i3] = float32[i3] / norm;
|
|
25870
|
+
}
|
|
25871
|
+
}
|
|
25872
|
+
return float32;
|
|
25873
|
+
}
|
|
25874
|
+
|
|
25936
25875
|
// packages/mcp-server/src/cli.ts
|
|
25937
25876
|
async function main() {
|
|
25938
25877
|
const supabaseUrl = process.env.SUPABASE_URL;
|
|
@@ -25946,52 +25885,22 @@ async function main() {
|
|
|
25946
25885
|
console.error("Error: OPENAI_API_KEY is required.\n");
|
|
25947
25886
|
process.exit(1);
|
|
25948
25887
|
}
|
|
25949
|
-
|
|
25950
|
-
|
|
25951
|
-
|
|
25952
|
-
createSupabaseClient2 = supa.createSupabaseClient;
|
|
25953
|
-
SupabaseStorageAdapter2 = supa.SupabaseStorageAdapter;
|
|
25954
|
-
const oai = await import("@steno-ai/openai-adapter");
|
|
25955
|
-
OpenAILLMAdapter2 = oai.OpenAILLMAdapter;
|
|
25956
|
-
} catch {
|
|
25957
|
-
const supa = await Promise.resolve().then(() => (init_src3(), src_exports));
|
|
25958
|
-
createSupabaseClient2 = supa.createSupabaseClient;
|
|
25959
|
-
SupabaseStorageAdapter2 = supa.SupabaseStorageAdapter;
|
|
25960
|
-
const oai = await Promise.resolve().then(() => (init_src4(), src_exports2));
|
|
25961
|
-
OpenAILLMAdapter2 = oai.OpenAILLMAdapter;
|
|
25962
|
-
}
|
|
25963
|
-
const supabase = createSupabaseClient2({ url: supabaseUrl, serviceRoleKey: supabaseKey });
|
|
25964
|
-
const storage = new SupabaseStorageAdapter2(supabase);
|
|
25965
|
-
const cheapLLM = new OpenAILLMAdapter2({ apiKey: openaiKey, model: "gpt-5.4-mini" });
|
|
25888
|
+
const supabase = createSupabaseClient({ url: supabaseUrl, serviceRoleKey: supabaseKey });
|
|
25889
|
+
const storage = new SupabaseStorageAdapter(supabase);
|
|
25890
|
+
const cheapLLM = new OpenAILLMAdapter({ apiKey: openaiKey, model: "gpt-5.4-mini" });
|
|
25966
25891
|
let embedding;
|
|
25967
25892
|
let embeddingModel;
|
|
25968
25893
|
let embeddingDim;
|
|
25969
25894
|
if (process.env.PERPLEXITY_API_KEY) {
|
|
25970
|
-
|
|
25971
|
-
|
|
25972
|
-
|
|
25973
|
-
|
|
25974
|
-
|
|
25975
|
-
dimensions: 2e3
|
|
25976
|
-
});
|
|
25977
|
-
} catch {
|
|
25978
|
-
const { PerplexityEmbeddingAdapter: PerplexityEmbeddingAdapter2 } = await Promise.resolve().then(() => (init_perplexity_embedding(), perplexity_embedding_exports));
|
|
25979
|
-
embedding = new PerplexityEmbeddingAdapter2({
|
|
25980
|
-
apiKey: process.env.PERPLEXITY_API_KEY,
|
|
25981
|
-
model: "pplx-embed-v1-4b",
|
|
25982
|
-
dimensions: 2e3
|
|
25983
|
-
});
|
|
25984
|
-
}
|
|
25895
|
+
embedding = new PerplexityEmbeddingAdapter({
|
|
25896
|
+
apiKey: process.env.PERPLEXITY_API_KEY,
|
|
25897
|
+
model: "pplx-embed-v1-4b",
|
|
25898
|
+
dimensions: 2e3
|
|
25899
|
+
});
|
|
25985
25900
|
embeddingModel = "pplx-embed-v1-4b";
|
|
25986
25901
|
embeddingDim = 2e3;
|
|
25987
25902
|
} else {
|
|
25988
|
-
|
|
25989
|
-
const { OpenAIEmbeddingAdapter: OpenAIEmbeddingAdapter2 } = await import("@steno-ai/openai-adapter");
|
|
25990
|
-
embedding = new OpenAIEmbeddingAdapter2({ apiKey: openaiKey, model: "text-embedding-3-large", dimensions: 3072 });
|
|
25991
|
-
} catch {
|
|
25992
|
-
const { OpenAIEmbeddingAdapter: OpenAIEmbeddingAdapter2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
|
|
25993
|
-
embedding = new OpenAIEmbeddingAdapter2({ apiKey: openaiKey, model: "text-embedding-3-large", dimensions: 3072 });
|
|
25994
|
-
}
|
|
25903
|
+
embedding = new OpenAIEmbeddingAdapter({ apiKey: openaiKey, model: "text-embedding-3-large", dimensions: 3072 });
|
|
25995
25904
|
embeddingModel = "text-embedding-3-large";
|
|
25996
25905
|
embeddingDim = 3072;
|
|
25997
25906
|
}
|