@stackbone/sdk 0.1.0-alpha.1 → 0.1.0-alpha.2
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/CHANGELOG.md +43 -0
- package/README.md +13 -12
- package/index.cjs +167 -231
- package/index.cjs.map +1 -1
- package/index.d.cts +64 -7
- package/index.d.ts +64 -7
- package/index.js +167 -231
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/stackbone-sdk-0.1.0-alpha.2.tgz +0 -0
- package/stackbone-sdk-0.1.0-alpha.1.tgz +0 -0
package/index.js
CHANGED
|
@@ -1786,9 +1786,9 @@ var nanoid = /^[a-zA-Z0-9_-]{21}$/;
|
|
|
1786
1786
|
var duration = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/;
|
|
1787
1787
|
var extendedDuration = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/;
|
|
1788
1788
|
var guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;
|
|
1789
|
-
var uuid = /* @__PURE__ */ __name((
|
|
1790
|
-
if (!
|
|
1791
|
-
return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${
|
|
1789
|
+
var uuid = /* @__PURE__ */ __name((version3) => {
|
|
1790
|
+
if (!version3) return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/;
|
|
1791
|
+
return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version3}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
|
|
1792
1792
|
}, "uuid");
|
|
1793
1793
|
var uuid4 = /* @__PURE__ */ uuid(4);
|
|
1794
1794
|
var uuid6 = /* @__PURE__ */ uuid(6);
|
|
@@ -14972,10 +14972,10 @@ function fromJSONSchema(schema, params) {
|
|
|
14972
14972
|
if (typeof schema === "boolean") {
|
|
14973
14973
|
return schema ? z.any() : z.never();
|
|
14974
14974
|
}
|
|
14975
|
-
const
|
|
14975
|
+
const version3 = detectVersion(schema, params?.defaultTarget);
|
|
14976
14976
|
const defs = schema.$defs || schema.definitions || {};
|
|
14977
14977
|
const ctx = {
|
|
14978
|
-
version:
|
|
14978
|
+
version: version3,
|
|
14979
14979
|
defs,
|
|
14980
14980
|
refs: /* @__PURE__ */ new Map(),
|
|
14981
14981
|
processing: /* @__PURE__ */ new Set(),
|
|
@@ -16644,6 +16644,34 @@ function pickDefinedAsStrings(source) {
|
|
|
16644
16644
|
}
|
|
16645
16645
|
__name(pickDefinedAsStrings, "pickDefinedAsStrings");
|
|
16646
16646
|
|
|
16647
|
+
// src/lib/facade-helpers.ts
|
|
16648
|
+
function remapHttpNotFound(code, domainCode, message, meta3) {
|
|
16649
|
+
if (code !== "http_not_found") return null;
|
|
16650
|
+
const error48 = {
|
|
16651
|
+
code: domainCode,
|
|
16652
|
+
message
|
|
16653
|
+
};
|
|
16654
|
+
if (meta3) error48.meta = meta3;
|
|
16655
|
+
return err(error48);
|
|
16656
|
+
}
|
|
16657
|
+
__name(remapHttpNotFound, "remapHttpNotFound");
|
|
16658
|
+
function validateStringArray(values, field, errorCode) {
|
|
16659
|
+
if (!Array.isArray(values) || values.length === 0) {
|
|
16660
|
+
return err({
|
|
16661
|
+
code: errorCode,
|
|
16662
|
+
message: `\`${field}\` must be a non-empty array.`
|
|
16663
|
+
});
|
|
16664
|
+
}
|
|
16665
|
+
if (values.some((v) => typeof v !== "string" || !v.trim())) {
|
|
16666
|
+
return err({
|
|
16667
|
+
code: errorCode,
|
|
16668
|
+
message: `\`${field}[*]\` must be non-empty strings.`
|
|
16669
|
+
});
|
|
16670
|
+
}
|
|
16671
|
+
return null;
|
|
16672
|
+
}
|
|
16673
|
+
__name(validateStringArray, "validateStringArray");
|
|
16674
|
+
|
|
16647
16675
|
// src/facades/config/config.ts
|
|
16648
16676
|
var ConfigFacade = class {
|
|
16649
16677
|
static {
|
|
@@ -16665,7 +16693,11 @@ var ConfigFacade = class {
|
|
|
16665
16693
|
const gateResult = await this._gate();
|
|
16666
16694
|
if (gateResult.error) return err(gateResult.error);
|
|
16667
16695
|
const result = await this._http.get(`/api/config/${encodeURIComponent(key)}`);
|
|
16668
|
-
if (result.error)
|
|
16696
|
+
if (result.error) {
|
|
16697
|
+
return remapHttpNotFound(result.error.code, "config_not_found", `Config key \`${key}\` is not set for this agent.`, {
|
|
16698
|
+
key
|
|
16699
|
+
}) ?? result;
|
|
16700
|
+
}
|
|
16669
16701
|
return ok(result.data.value);
|
|
16670
16702
|
}
|
|
16671
16703
|
/**
|
|
@@ -16675,18 +16707,8 @@ var ConfigFacade = class {
|
|
|
16675
16707
|
* is `Partial<T>`).
|
|
16676
16708
|
*/
|
|
16677
16709
|
async getMany(keys) {
|
|
16678
|
-
|
|
16679
|
-
|
|
16680
|
-
code: "config_invalid_request",
|
|
16681
|
-
message: "`keys` must be a non-empty array."
|
|
16682
|
-
});
|
|
16683
|
-
}
|
|
16684
|
-
if (keys.some((k) => !k.trim())) {
|
|
16685
|
-
return err({
|
|
16686
|
-
code: "config_invalid_request",
|
|
16687
|
-
message: "`keys[*]` must be non-empty strings."
|
|
16688
|
-
});
|
|
16689
|
-
}
|
|
16710
|
+
const invalid = validateStringArray(keys, "keys", "config_invalid_request");
|
|
16711
|
+
if (invalid) return invalid;
|
|
16690
16712
|
const gateResult = await this._gate();
|
|
16691
16713
|
if (gateResult.error) return err(gateResult.error);
|
|
16692
16714
|
const result = await this._http.get("/api/config", {
|
|
@@ -16705,17 +16727,6 @@ var ConfigFacade = class {
|
|
|
16705
16727
|
return ok(values);
|
|
16706
16728
|
}
|
|
16707
16729
|
};
|
|
16708
|
-
function remapNotFound(code, key) {
|
|
16709
|
-
if (code !== "http_not_found") return null;
|
|
16710
|
-
return err({
|
|
16711
|
-
code: "config_not_found",
|
|
16712
|
-
message: `Config key \`${key}\` is not set for this agent.`,
|
|
16713
|
-
meta: {
|
|
16714
|
-
key
|
|
16715
|
-
}
|
|
16716
|
-
});
|
|
16717
|
-
}
|
|
16718
|
-
__name(remapNotFound, "remapNotFound");
|
|
16719
16730
|
|
|
16720
16731
|
// src/facades/connections/connections.ts
|
|
16721
16732
|
var ConnectionsFacade = class {
|
|
@@ -16801,7 +16812,11 @@ var SecretsFacade = class {
|
|
|
16801
16812
|
const gateResult = await this._gate();
|
|
16802
16813
|
if (gateResult.error) return err(gateResult.error);
|
|
16803
16814
|
const result = await this._http.get(`/api/secrets/${encodeURIComponent(name)}`);
|
|
16804
|
-
if (result.error)
|
|
16815
|
+
if (result.error) {
|
|
16816
|
+
return remapHttpNotFound(result.error.code, "secrets_not_found", `Secret \`${name}\` is not registered for this organization.`, {
|
|
16817
|
+
name
|
|
16818
|
+
}) ?? result;
|
|
16819
|
+
}
|
|
16805
16820
|
if (typeof result.data.value !== "string") {
|
|
16806
16821
|
return err({
|
|
16807
16822
|
code: "secrets_invalid_response",
|
|
@@ -16814,23 +16829,13 @@ var SecretsFacade = class {
|
|
|
16814
16829
|
return ok(result.data.value);
|
|
16815
16830
|
}
|
|
16816
16831
|
/**
|
|
16817
|
-
* Names absent from the
|
|
16832
|
+
* Names absent from the organization come back as omissions in the response —
|
|
16818
16833
|
* the returned map only contains entries the control plane actually has.
|
|
16819
16834
|
* Callers that need "all-or-nothing" semantics should diff the keys.
|
|
16820
16835
|
*/
|
|
16821
16836
|
async getMany(names) {
|
|
16822
|
-
|
|
16823
|
-
|
|
16824
|
-
code: "secrets_invalid_request",
|
|
16825
|
-
message: "`names` must be a non-empty array."
|
|
16826
|
-
});
|
|
16827
|
-
}
|
|
16828
|
-
if (names.some((n) => !n.trim())) {
|
|
16829
|
-
return err({
|
|
16830
|
-
code: "secrets_invalid_request",
|
|
16831
|
-
message: "`names[*]` must be non-empty strings."
|
|
16832
|
-
});
|
|
16833
|
-
}
|
|
16837
|
+
const invalid = validateStringArray(names, "names", "secrets_invalid_request");
|
|
16838
|
+
if (invalid) return invalid;
|
|
16834
16839
|
const gateResult = await this._gate();
|
|
16835
16840
|
if (gateResult.error) return err(gateResult.error);
|
|
16836
16841
|
const result = await this._http.get("/api/secrets", {
|
|
@@ -16849,17 +16854,6 @@ var SecretsFacade = class {
|
|
|
16849
16854
|
return ok(values);
|
|
16850
16855
|
}
|
|
16851
16856
|
};
|
|
16852
|
-
function remapNotFound2(code, name) {
|
|
16853
|
-
if (code !== "http_not_found") return null;
|
|
16854
|
-
return err({
|
|
16855
|
-
code: "secrets_not_found",
|
|
16856
|
-
message: `Secret \`${name}\` is not registered for this workspace.`,
|
|
16857
|
-
meta: {
|
|
16858
|
-
name
|
|
16859
|
-
}
|
|
16860
|
-
});
|
|
16861
|
-
}
|
|
16862
|
-
__name(remapNotFound2, "remapNotFound");
|
|
16863
16857
|
|
|
16864
16858
|
// src/lib/http-client.ts
|
|
16865
16859
|
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([
|
|
@@ -17742,6 +17736,11 @@ async function aggregateRunCost(runId, options) {
|
|
|
17742
17736
|
};
|
|
17743
17737
|
}
|
|
17744
17738
|
__name(aggregateRunCost, "aggregateRunCost");
|
|
17739
|
+
|
|
17740
|
+
// package.json
|
|
17741
|
+
var version2 = "0.1.0-alpha.2";
|
|
17742
|
+
|
|
17743
|
+
// src/observability/logger.ts
|
|
17745
17744
|
var LOG_LEVELS = {
|
|
17746
17745
|
trace: 10,
|
|
17747
17746
|
debug: 20,
|
|
@@ -17955,7 +17954,7 @@ var OtlpHttpDestination = class OtlpHttpDestination2 {
|
|
|
17955
17954
|
};
|
|
17956
17955
|
var SDK_SCOPE = {
|
|
17957
17956
|
name: "@stackbone/sdk",
|
|
17958
|
-
version:
|
|
17957
|
+
version: version2
|
|
17959
17958
|
};
|
|
17960
17959
|
function buildOtlpLogsBody(records, resourceAttributes) {
|
|
17961
17960
|
return {
|
|
@@ -17988,11 +17987,12 @@ function toOtlpLogRecord(record2) {
|
|
|
17988
17987
|
};
|
|
17989
17988
|
}
|
|
17990
17989
|
__name(toOtlpLogRecord, "toOtlpLogRecord");
|
|
17990
|
+
var SEVERITY_TEXT_BY_LEVEL = Object.fromEntries(Object.entries(LOG_LEVELS).map(([name, value]) => [
|
|
17991
|
+
value,
|
|
17992
|
+
name.toUpperCase()
|
|
17993
|
+
]));
|
|
17991
17994
|
function severityText(level) {
|
|
17992
|
-
|
|
17993
|
-
if (value === level) return name.toUpperCase();
|
|
17994
|
-
}
|
|
17995
|
-
return "INFO";
|
|
17995
|
+
return SEVERITY_TEXT_BY_LEVEL[level] ?? "INFO";
|
|
17996
17996
|
}
|
|
17997
17997
|
__name(severityText, "severityText");
|
|
17998
17998
|
function toOtlpAttributes(attrs) {
|
|
@@ -18160,11 +18160,11 @@ var RunStepsSpanProcessor = class {
|
|
|
18160
18160
|
}
|
|
18161
18161
|
}
|
|
18162
18162
|
buildRow(span) {
|
|
18163
|
-
const runId = readString(span.attributes[RUN_ID_ATTRIBUTE]);
|
|
18164
|
-
if (!runId) return null;
|
|
18165
18163
|
const spanId = span.spanContext().spanId;
|
|
18166
18164
|
const stepId = this.stepIdBySpanId.get(spanId) ?? this.newId();
|
|
18167
18165
|
this.stepIdBySpanId.delete(spanId);
|
|
18166
|
+
const runId = readString(span.attributes[RUN_ID_ATTRIBUTE]);
|
|
18167
|
+
if (!runId) return null;
|
|
18168
18168
|
const parentSpanId = span.parentSpanContext?.spanId ?? span.parentSpanId ?? null;
|
|
18169
18169
|
const parentStepId = parentSpanId ? this.stepIdBySpanId.get(parentSpanId) ?? null : null;
|
|
18170
18170
|
const startedAt = formatHrTime(span.startTime);
|
|
@@ -18614,6 +18614,41 @@ function isUnsupportedModelError(error48) {
|
|
|
18614
18614
|
}
|
|
18615
18615
|
__name(isUnsupportedModelError, "isUnsupportedModelError");
|
|
18616
18616
|
|
|
18617
|
+
// src/modules/rag/errors.ts
|
|
18618
|
+
var PG_UNDEFINED_TABLE = "42P01";
|
|
18619
|
+
var RAG_SCHEMA_MISSING_HINT = "run `stackbone db migrate add-rag` and `stackbone db migrate up`";
|
|
18620
|
+
function isTaggedError(cause) {
|
|
18621
|
+
return cause instanceof Error;
|
|
18622
|
+
}
|
|
18623
|
+
__name(isTaggedError, "isTaggedError");
|
|
18624
|
+
function toRagError(cause, message, fallbackCode = "rag_error") {
|
|
18625
|
+
if (isTaggedError(cause) && cause.code === PG_UNDEFINED_TABLE) {
|
|
18626
|
+
return {
|
|
18627
|
+
code: "rag_schema_missing",
|
|
18628
|
+
message: `RAG tables are not installed \u2014 ${RAG_SCHEMA_MISSING_HINT}.`,
|
|
18629
|
+
cause,
|
|
18630
|
+
meta: {
|
|
18631
|
+
hint: RAG_SCHEMA_MISSING_HINT
|
|
18632
|
+
}
|
|
18633
|
+
};
|
|
18634
|
+
}
|
|
18635
|
+
if (isTaggedError(cause)) {
|
|
18636
|
+
const error48 = {
|
|
18637
|
+
code: cause.code ?? fallbackCode,
|
|
18638
|
+
message: `${message}: ${cause.message}`,
|
|
18639
|
+
cause
|
|
18640
|
+
};
|
|
18641
|
+
if (cause.meta) error48.meta = cause.meta;
|
|
18642
|
+
return error48;
|
|
18643
|
+
}
|
|
18644
|
+
return {
|
|
18645
|
+
code: fallbackCode,
|
|
18646
|
+
message,
|
|
18647
|
+
cause
|
|
18648
|
+
};
|
|
18649
|
+
}
|
|
18650
|
+
__name(toRagError, "toRagError");
|
|
18651
|
+
|
|
18617
18652
|
// src/modules/rag/jobs.ts
|
|
18618
18653
|
function createSqlJobWriter(sql) {
|
|
18619
18654
|
return {
|
|
@@ -18639,7 +18674,7 @@ function createSqlJobWriter(sql) {
|
|
|
18639
18674
|
jobId: row.id
|
|
18640
18675
|
});
|
|
18641
18676
|
} catch (cause) {
|
|
18642
|
-
return err(
|
|
18677
|
+
return err(toRagError(cause, "Job start failed", "rag_jobs_error"));
|
|
18643
18678
|
}
|
|
18644
18679
|
},
|
|
18645
18680
|
async progress({ jobId, processedChunks, totalChunks, currentDocument }) {
|
|
@@ -18678,7 +18713,7 @@ function createSqlJobWriter(sql) {
|
|
|
18678
18713
|
},
|
|
18679
18714
|
async isCancelled({ jobId }) {
|
|
18680
18715
|
const rows = await sql`
|
|
18681
|
-
SELECT
|
|
18716
|
+
SELECT status FROM stackbone_rag_jobs WHERE id = ${jobId} LIMIT 1
|
|
18682
18717
|
`;
|
|
18683
18718
|
return rows[0]?.status === "cancelled";
|
|
18684
18719
|
}
|
|
@@ -18686,10 +18721,6 @@ function createSqlJobWriter(sql) {
|
|
|
18686
18721
|
}
|
|
18687
18722
|
__name(createSqlJobWriter, "createSqlJobWriter");
|
|
18688
18723
|
async function ensureCollection(sql, name) {
|
|
18689
|
-
const existing = await sql`
|
|
18690
|
-
SELECT id FROM stackbone_rag_collections WHERE name = ${name} LIMIT 1
|
|
18691
|
-
`;
|
|
18692
|
-
if (existing[0]) return existing[0].id;
|
|
18693
18724
|
const inserted = await sql`
|
|
18694
18725
|
INSERT INTO stackbone_rag_collections (name) VALUES (${name})
|
|
18695
18726
|
ON CONFLICT (name) DO UPDATE SET name = EXCLUDED.name
|
|
@@ -18697,37 +18728,11 @@ async function ensureCollection(sql, name) {
|
|
|
18697
18728
|
`;
|
|
18698
18729
|
const row = inserted[0];
|
|
18699
18730
|
if (!row) {
|
|
18700
|
-
throw new Error(`stackbone_rag_collections
|
|
18731
|
+
throw new Error(`stackbone_rag_collections upsert returned no row for ${name}`);
|
|
18701
18732
|
}
|
|
18702
18733
|
return row.id;
|
|
18703
18734
|
}
|
|
18704
18735
|
__name(ensureCollection, "ensureCollection");
|
|
18705
|
-
function toJobsError(cause, message) {
|
|
18706
|
-
if (cause instanceof Error) {
|
|
18707
|
-
const tagged = cause;
|
|
18708
|
-
if (tagged.code === "42P01") {
|
|
18709
|
-
return {
|
|
18710
|
-
code: "rag_schema_missing",
|
|
18711
|
-
message: "RAG tables are not installed \u2014 run `stackbone db migrate add-rag` and `stackbone db migrate up`.",
|
|
18712
|
-
cause,
|
|
18713
|
-
meta: {
|
|
18714
|
-
hint: "run `stackbone db migrate add-rag` and `stackbone db migrate up`"
|
|
18715
|
-
}
|
|
18716
|
-
};
|
|
18717
|
-
}
|
|
18718
|
-
return {
|
|
18719
|
-
code: tagged.code ?? "rag_jobs_error",
|
|
18720
|
-
message: `${message}: ${cause.message}`,
|
|
18721
|
-
cause
|
|
18722
|
-
};
|
|
18723
|
-
}
|
|
18724
|
-
return {
|
|
18725
|
-
code: "rag_jobs_error",
|
|
18726
|
-
message,
|
|
18727
|
-
cause
|
|
18728
|
-
};
|
|
18729
|
-
}
|
|
18730
|
-
__name(toJobsError, "toJobsError");
|
|
18731
18736
|
var PDF_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
18732
18737
|
"application/pdf",
|
|
18733
18738
|
"application/x-pdf"
|
|
@@ -18787,10 +18792,12 @@ __name(looksLikePdf, "looksLikePdf");
|
|
|
18787
18792
|
var DEFAULT_NAMESPACE = "default";
|
|
18788
18793
|
var META_KEY_DIMENSIONS = "dimensions";
|
|
18789
18794
|
var META_KEY_DISTANCE = "distance";
|
|
18795
|
+
var schemaVerifiedDimensions = /* @__PURE__ */ new WeakMap();
|
|
18790
18796
|
async function ensureSchema(sql, dimensions) {
|
|
18791
18797
|
if (!Number.isInteger(dimensions) || dimensions <= 0 || dimensions > 8192) {
|
|
18792
18798
|
throw new Error(`rag.ensureSchema: invalid dimensions ${dimensions}. Must be a positive integer <= 8192.`);
|
|
18793
18799
|
}
|
|
18800
|
+
if (schemaVerifiedDimensions.get(sql) === dimensions) return;
|
|
18794
18801
|
const existing = await sql`
|
|
18795
18802
|
SELECT value::int AS value FROM _rag_meta WHERE key = ${META_KEY_DIMENSIONS}
|
|
18796
18803
|
`.catch(() => []);
|
|
@@ -18805,6 +18812,7 @@ async function ensureSchema(sql, dimensions) {
|
|
|
18805
18812
|
};
|
|
18806
18813
|
throw error48;
|
|
18807
18814
|
}
|
|
18815
|
+
schemaVerifiedDimensions.set(sql, dimensions);
|
|
18808
18816
|
return;
|
|
18809
18817
|
}
|
|
18810
18818
|
await sql.begin(async (tx) => {
|
|
@@ -18824,6 +18832,7 @@ async function ensureSchema(sql, dimensions) {
|
|
|
18824
18832
|
ON CONFLICT (key) DO NOTHING
|
|
18825
18833
|
`;
|
|
18826
18834
|
});
|
|
18835
|
+
schemaVerifiedDimensions.set(sql, dimensions);
|
|
18827
18836
|
}
|
|
18828
18837
|
__name(ensureSchema, "ensureSchema");
|
|
18829
18838
|
async function reset(sql) {
|
|
@@ -18831,29 +18840,31 @@ async function reset(sql) {
|
|
|
18831
18840
|
await tx`DROP TABLE IF EXISTS rag_chunks`;
|
|
18832
18841
|
await tx`DROP TABLE IF EXISTS _rag_meta`;
|
|
18833
18842
|
});
|
|
18843
|
+
schemaVerifiedDimensions.delete(sql);
|
|
18834
18844
|
}
|
|
18835
18845
|
__name(reset, "reset");
|
|
18836
|
-
async function
|
|
18846
|
+
async function clearDocument(sql, docId, namespace) {
|
|
18847
|
+
await sql`
|
|
18848
|
+
DELETE FROM rag_chunks
|
|
18849
|
+
WHERE namespace = ${namespace} AND doc_id = ${docId}
|
|
18850
|
+
`;
|
|
18851
|
+
}
|
|
18852
|
+
__name(clearDocument, "clearDocument");
|
|
18853
|
+
async function ingestDocument(sql, rows) {
|
|
18837
18854
|
if (rows.length === 0) return 0;
|
|
18838
|
-
|
|
18839
|
-
|
|
18840
|
-
|
|
18841
|
-
|
|
18842
|
-
|
|
18843
|
-
|
|
18844
|
-
|
|
18845
|
-
|
|
18846
|
-
|
|
18847
|
-
|
|
18848
|
-
|
|
18849
|
-
|
|
18850
|
-
|
|
18851
|
-
row.content,
|
|
18852
|
-
formatVector(row.embedding),
|
|
18853
|
-
JSON.stringify(row.metadata)
|
|
18854
|
-
]);
|
|
18855
|
-
await tx.unsafe(`INSERT INTO rag_chunks (doc_id, chunk_idx, namespace, content, embedding, metadata) VALUES ${placeholders}`, params);
|
|
18856
|
-
});
|
|
18855
|
+
const placeholders = rows.map((_, i) => {
|
|
18856
|
+
const base = i * 6;
|
|
18857
|
+
return `($${base + 1}, $${base + 2}, $${base + 3}, $${base + 4}, $${base + 5}::vector, $${base + 6}::jsonb)`;
|
|
18858
|
+
}).join(",");
|
|
18859
|
+
const params = rows.flatMap((row) => [
|
|
18860
|
+
row.docId,
|
|
18861
|
+
row.chunkIdx,
|
|
18862
|
+
row.namespace,
|
|
18863
|
+
row.content,
|
|
18864
|
+
formatVector(row.embedding),
|
|
18865
|
+
JSON.stringify(row.metadata)
|
|
18866
|
+
]);
|
|
18867
|
+
await sql.unsafe(`INSERT INTO rag_chunks (doc_id, chunk_idx, namespace, content, embedding, metadata) VALUES ${placeholders}`, params);
|
|
18857
18868
|
return rows.length;
|
|
18858
18869
|
}
|
|
18859
18870
|
__name(ingestDocument, "ingestDocument");
|
|
@@ -18923,8 +18934,6 @@ var CHUNK_INDEXES_DDL = `
|
|
|
18923
18934
|
|
|
18924
18935
|
// src/modules/rag/pipeline.ts
|
|
18925
18936
|
var DEFAULT_TOP_K = 5;
|
|
18926
|
-
var RAG_SCHEMA_MISSING_HINT = "run `stackbone db migrate add-rag` and `stackbone db migrate up`";
|
|
18927
|
-
var PG_UNDEFINED_TABLE = "42P01";
|
|
18928
18937
|
var RagPipeline = class {
|
|
18929
18938
|
static {
|
|
18930
18939
|
__name(this, "RagPipeline");
|
|
@@ -18989,19 +18998,16 @@ var RagPipeline = class {
|
|
|
18989
18998
|
if (started.error) return err(started.error);
|
|
18990
18999
|
jobId = started.data.jobId;
|
|
18991
19000
|
}
|
|
18992
|
-
|
|
18993
|
-
if (onProgress) await onProgress(event);
|
|
18994
|
-
}, "emit");
|
|
18995
|
-
const startEvent = {
|
|
19001
|
+
await onProgress?.({
|
|
18996
19002
|
type: "started",
|
|
18997
19003
|
jobId: jobId ?? request.id,
|
|
18998
19004
|
totalChunks
|
|
18999
|
-
};
|
|
19000
|
-
await emit(startEvent);
|
|
19005
|
+
});
|
|
19001
19006
|
try {
|
|
19002
19007
|
await ensureSchema(sql.data, dimensions);
|
|
19003
19008
|
const needsBatching = Boolean(writer || onProgress);
|
|
19004
19009
|
const batchSize = this._progressBatchSize ?? (needsBatching ? 1 : rows.length || 1);
|
|
19010
|
+
await clearDocument(sql.data, request.id, namespace);
|
|
19005
19011
|
let processed = 0;
|
|
19006
19012
|
for (let offset = 0; offset < rows.length; offset += batchSize) {
|
|
19007
19013
|
if (writer && jobId) {
|
|
@@ -19021,37 +19027,33 @@ var RagPipeline = class {
|
|
|
19021
19027
|
}
|
|
19022
19028
|
}
|
|
19023
19029
|
const slice = rows.slice(offset, offset + batchSize);
|
|
19024
|
-
await ingestDocument(sql.data,
|
|
19030
|
+
await ingestDocument(sql.data, slice);
|
|
19025
19031
|
processed += slice.length;
|
|
19026
|
-
const
|
|
19032
|
+
const currentDocument = {
|
|
19033
|
+
source: request.id,
|
|
19034
|
+
ordinal: processed - 1
|
|
19035
|
+
};
|
|
19036
|
+
await onProgress?.({
|
|
19027
19037
|
type: "progress",
|
|
19028
19038
|
jobId: jobId ?? request.id,
|
|
19029
19039
|
processedChunks: processed,
|
|
19030
19040
|
totalChunks,
|
|
19031
|
-
currentDocument
|
|
19032
|
-
|
|
19033
|
-
ordinal: processed - 1
|
|
19034
|
-
}
|
|
19035
|
-
};
|
|
19036
|
-
await emit(progressEvent);
|
|
19041
|
+
currentDocument
|
|
19042
|
+
});
|
|
19037
19043
|
if (writer && jobId) {
|
|
19038
19044
|
await writer.progress({
|
|
19039
19045
|
jobId,
|
|
19040
19046
|
processedChunks: processed,
|
|
19041
19047
|
totalChunks,
|
|
19042
|
-
currentDocument
|
|
19043
|
-
source: request.id,
|
|
19044
|
-
ordinal: processed - 1
|
|
19045
|
-
}
|
|
19048
|
+
currentDocument
|
|
19046
19049
|
});
|
|
19047
19050
|
}
|
|
19048
19051
|
}
|
|
19049
|
-
|
|
19052
|
+
await onProgress?.({
|
|
19050
19053
|
type: "completed",
|
|
19051
19054
|
jobId: jobId ?? request.id,
|
|
19052
19055
|
totalChunks
|
|
19053
|
-
};
|
|
19054
|
-
await emit(completedEvent);
|
|
19056
|
+
});
|
|
19055
19057
|
if (writer && jobId) await writer.complete({
|
|
19056
19058
|
jobId,
|
|
19057
19059
|
totalChunks
|
|
@@ -19062,12 +19064,11 @@ var RagPipeline = class {
|
|
|
19062
19064
|
});
|
|
19063
19065
|
} catch (cause) {
|
|
19064
19066
|
const mapped = toRagError(cause, "Ingest failed");
|
|
19065
|
-
|
|
19067
|
+
await onProgress?.({
|
|
19066
19068
|
type: "failed",
|
|
19067
19069
|
jobId: jobId ?? request.id,
|
|
19068
19070
|
error: mapped.message
|
|
19069
|
-
};
|
|
19070
|
-
await emit(failedEvent);
|
|
19071
|
+
});
|
|
19071
19072
|
if (writer && jobId) await writer.fail({
|
|
19072
19073
|
jobId,
|
|
19073
19074
|
error: mapped.message
|
|
@@ -19227,37 +19228,6 @@ function validateIngest(request, hasEmbedder) {
|
|
|
19227
19228
|
return ok(true);
|
|
19228
19229
|
}
|
|
19229
19230
|
__name(validateIngest, "validateIngest");
|
|
19230
|
-
function isTaggedError(cause) {
|
|
19231
|
-
return cause instanceof Error;
|
|
19232
|
-
}
|
|
19233
|
-
__name(isTaggedError, "isTaggedError");
|
|
19234
|
-
function toRagError(cause, message) {
|
|
19235
|
-
if (isTaggedError(cause) && cause.code === PG_UNDEFINED_TABLE) {
|
|
19236
|
-
return {
|
|
19237
|
-
code: "rag_schema_missing",
|
|
19238
|
-
message: `RAG tables are not installed \u2014 ${RAG_SCHEMA_MISSING_HINT}.`,
|
|
19239
|
-
cause,
|
|
19240
|
-
meta: {
|
|
19241
|
-
hint: RAG_SCHEMA_MISSING_HINT
|
|
19242
|
-
}
|
|
19243
|
-
};
|
|
19244
|
-
}
|
|
19245
|
-
if (isTaggedError(cause)) {
|
|
19246
|
-
const error48 = {
|
|
19247
|
-
code: cause.code ?? "rag_error",
|
|
19248
|
-
message: `${message}: ${cause.message}`,
|
|
19249
|
-
cause
|
|
19250
|
-
};
|
|
19251
|
-
if (cause.meta) error48.meta = cause.meta;
|
|
19252
|
-
return error48;
|
|
19253
|
-
}
|
|
19254
|
-
return {
|
|
19255
|
-
code: "rag_error",
|
|
19256
|
-
message,
|
|
19257
|
-
cause
|
|
19258
|
-
};
|
|
19259
|
-
}
|
|
19260
|
-
__name(toRagError, "toRagError");
|
|
19261
19231
|
|
|
19262
19232
|
// src/modules/rag/rag.ts
|
|
19263
19233
|
var DEFAULT_BATCH_SIZE4 = 128;
|
|
@@ -19269,10 +19239,14 @@ var RagModule = class {
|
|
|
19269
19239
|
_resolved;
|
|
19270
19240
|
_getAi;
|
|
19271
19241
|
_gate;
|
|
19272
|
-
|
|
19242
|
+
_testSqlOverride;
|
|
19243
|
+
_testJobWriterFactory;
|
|
19244
|
+
constructor(_resolved, _getAi, gate, testDeps) {
|
|
19273
19245
|
this._resolved = _resolved;
|
|
19274
19246
|
this._getAi = _getAi;
|
|
19275
19247
|
this._gate = gate ?? createModuleGate("rag", _resolved);
|
|
19248
|
+
if (testDeps?.sqlProvider) this._testSqlOverride = testDeps.sqlProvider;
|
|
19249
|
+
if (testDeps?.jobWriterFactory) this._testJobWriterFactory = testDeps.jobWriterFactory;
|
|
19276
19250
|
}
|
|
19277
19251
|
async ingest(request) {
|
|
19278
19252
|
const gateResult = await this._gate();
|
|
@@ -19305,7 +19279,8 @@ var RagModule = class {
|
|
|
19305
19279
|
if (gateResult.error) return err(gateResult.error);
|
|
19306
19280
|
const sql = this._testSqlOverride ? this._testSqlOverride() : this.sql();
|
|
19307
19281
|
if (sql.error) return err(sql.error);
|
|
19308
|
-
const
|
|
19282
|
+
const writerFactory = this._testJobWriterFactory ?? createSqlJobWriter;
|
|
19283
|
+
const writer = writerFactory(sql.data);
|
|
19309
19284
|
const channel = createProgressChannel();
|
|
19310
19285
|
const resolved = resolveIngestModel(request, this._resolved);
|
|
19311
19286
|
const requestWithHook = {
|
|
@@ -19336,7 +19311,7 @@ var RagModule = class {
|
|
|
19336
19311
|
return r;
|
|
19337
19312
|
}).catch((cause) => {
|
|
19338
19313
|
channel.close();
|
|
19339
|
-
return err(
|
|
19314
|
+
return err(toRagError(cause, "Ingest failed"));
|
|
19340
19315
|
});
|
|
19341
19316
|
return ok({
|
|
19342
19317
|
jobId,
|
|
@@ -19344,10 +19319,6 @@ var RagModule = class {
|
|
|
19344
19319
|
result
|
|
19345
19320
|
});
|
|
19346
19321
|
}
|
|
19347
|
-
/** Test-only seam — assigned by `ingest-async.spec.ts`. */
|
|
19348
|
-
_testJobWriter;
|
|
19349
|
-
/** Test-only seam — assigned by `ingest-async.spec.ts`. */
|
|
19350
|
-
_testSqlOverride;
|
|
19351
19322
|
async delete(ids, options) {
|
|
19352
19323
|
const gateResult = await this._gate();
|
|
19353
19324
|
if (gateResult.error) return err(gateResult.error);
|
|
@@ -19379,7 +19350,7 @@ var RagModule = class {
|
|
|
19379
19350
|
await reset(sql.data);
|
|
19380
19351
|
return ok(void 0);
|
|
19381
19352
|
} catch (cause) {
|
|
19382
|
-
return err(
|
|
19353
|
+
return err(toRagError(cause, "Reset failed"));
|
|
19383
19354
|
}
|
|
19384
19355
|
}
|
|
19385
19356
|
/**
|
|
@@ -19407,22 +19378,18 @@ var RagModule = class {
|
|
|
19407
19378
|
* `Result.err` with the same `database_not_configured` shape `client.database`
|
|
19408
19379
|
* raises, instead of throwing through the public surface.
|
|
19409
19380
|
*/
|
|
19410
|
-
// `_resolved` is reserved for future per-config overrides (e.g. routing
|
|
19411
|
-
// RAG queries through a logical replica). The URL itself is owned by the
|
|
19412
|
-
// shared handle.
|
|
19413
19381
|
sql() {
|
|
19414
|
-
void this._resolved;
|
|
19415
19382
|
try {
|
|
19416
19383
|
return ok(getDatabaseHandle().$client);
|
|
19417
19384
|
} catch (cause) {
|
|
19418
|
-
if (
|
|
19385
|
+
if (isTaggedError(cause) && cause.code === "database_not_configured") {
|
|
19419
19386
|
return err({
|
|
19420
19387
|
code: "database_not_configured",
|
|
19421
19388
|
message: cause.message,
|
|
19422
19389
|
cause
|
|
19423
19390
|
});
|
|
19424
19391
|
}
|
|
19425
|
-
return err(
|
|
19392
|
+
return err(toRagError(cause, "Database handle unavailable"));
|
|
19426
19393
|
}
|
|
19427
19394
|
}
|
|
19428
19395
|
async withPipeline(embedder, run) {
|
|
@@ -19543,27 +19510,6 @@ function resolveRetrieveModel(request, resolved) {
|
|
|
19543
19510
|
};
|
|
19544
19511
|
}
|
|
19545
19512
|
__name(resolveRetrieveModel, "resolveRetrieveModel");
|
|
19546
|
-
function isTaggedError2(cause) {
|
|
19547
|
-
return cause instanceof Error;
|
|
19548
|
-
}
|
|
19549
|
-
__name(isTaggedError2, "isTaggedError");
|
|
19550
|
-
function toRagError2(cause, message) {
|
|
19551
|
-
if (isTaggedError2(cause)) {
|
|
19552
|
-
const error48 = {
|
|
19553
|
-
code: cause.code ?? "rag_error",
|
|
19554
|
-
message: `${message}: ${cause.message}`,
|
|
19555
|
-
cause
|
|
19556
|
-
};
|
|
19557
|
-
if (cause.meta) error48.meta = cause.meta;
|
|
19558
|
-
return error48;
|
|
19559
|
-
}
|
|
19560
|
-
return {
|
|
19561
|
-
code: "rag_error",
|
|
19562
|
-
message,
|
|
19563
|
-
cause
|
|
19564
|
-
};
|
|
19565
|
-
}
|
|
19566
|
-
__name(toRagError2, "toRagError");
|
|
19567
19513
|
var DEFAULT_SIGNED_URL_TTL_SECONDS = 3600;
|
|
19568
19514
|
var StorageModule = class {
|
|
19569
19515
|
static {
|
|
@@ -19765,29 +19711,19 @@ var StorageBucket = class {
|
|
|
19765
19711
|
return ok(`${base}/${bucket}/${encodeS3Key(fullKey)}`);
|
|
19766
19712
|
}
|
|
19767
19713
|
async getSignedUploadUrl(key, options) {
|
|
19768
|
-
|
|
19769
|
-
|
|
19770
|
-
|
|
19771
|
-
|
|
19772
|
-
|
|
19773
|
-
const expiresIn = options?.expiresIn ?? DEFAULT_SIGNED_URL_TTL_SECONDS;
|
|
19774
|
-
try {
|
|
19775
|
-
const url2 = await getSignedUrl(client, new PutObjectCommand({
|
|
19776
|
-
Bucket: bucket,
|
|
19777
|
-
Key: fullKey,
|
|
19778
|
-
ContentType: options?.contentType
|
|
19779
|
-
}), {
|
|
19780
|
-
expiresIn
|
|
19781
|
-
});
|
|
19782
|
-
return ok({
|
|
19783
|
-
url: url2,
|
|
19784
|
-
expiresAt: new Date(Date.now() + expiresIn * 1e3)
|
|
19785
|
-
});
|
|
19786
|
-
} catch (cause) {
|
|
19787
|
-
return err(toStorageError("Signing upload URL failed", cause));
|
|
19788
|
-
}
|
|
19714
|
+
return this.signUrl(key, options, "Signing upload URL failed", ({ bucket, fullKey }) => new PutObjectCommand({
|
|
19715
|
+
Bucket: bucket,
|
|
19716
|
+
Key: fullKey,
|
|
19717
|
+
ContentType: options?.contentType
|
|
19718
|
+
}));
|
|
19789
19719
|
}
|
|
19790
19720
|
async getSignedDownloadUrl(key, options) {
|
|
19721
|
+
return this.signUrl(key, options, "Signing download URL failed", ({ bucket, fullKey }) => new GetObjectCommand({
|
|
19722
|
+
Bucket: bucket,
|
|
19723
|
+
Key: fullKey
|
|
19724
|
+
}));
|
|
19725
|
+
}
|
|
19726
|
+
async signUrl(key, options, failureMessage, buildCommand) {
|
|
19791
19727
|
const gateResult = await this.gate();
|
|
19792
19728
|
if (gateResult.error) return err(gateResult.error);
|
|
19793
19729
|
const resolved = this.resolve(key);
|
|
@@ -19795,9 +19731,9 @@ var StorageBucket = class {
|
|
|
19795
19731
|
const { client, bucket, fullKey } = resolved.data;
|
|
19796
19732
|
const expiresIn = options?.expiresIn ?? DEFAULT_SIGNED_URL_TTL_SECONDS;
|
|
19797
19733
|
try {
|
|
19798
|
-
const url2 = await getSignedUrl(client,
|
|
19799
|
-
|
|
19800
|
-
|
|
19734
|
+
const url2 = await getSignedUrl(client, buildCommand({
|
|
19735
|
+
bucket,
|
|
19736
|
+
fullKey
|
|
19801
19737
|
}), {
|
|
19802
19738
|
expiresIn
|
|
19803
19739
|
});
|
|
@@ -19806,7 +19742,7 @@ var StorageBucket = class {
|
|
|
19806
19742
|
expiresAt: new Date(Date.now() + expiresIn * 1e3)
|
|
19807
19743
|
});
|
|
19808
19744
|
} catch (cause) {
|
|
19809
|
-
return err(toStorageError(
|
|
19745
|
+
return err(toStorageError(failureMessage, cause));
|
|
19810
19746
|
}
|
|
19811
19747
|
}
|
|
19812
19748
|
/**
|