@stackbone/sdk 0.1.0-alpha.5 → 0.1.0-alpha.6
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 +2 -0
- package/index.cjs +106 -36
- package/index.cjs.map +1 -1
- package/index.d.cts +126 -4
- package/index.d.ts +126 -4
- package/index.js +106 -36
- package/index.js.map +1 -1
- package/observability/index.cjs +1 -1
- package/observability/index.cjs.map +1 -1
- package/observability/index.d.cts +1 -1
- package/observability/index.d.ts +1 -1
- package/observability/index.js +1 -1
- package/observability/index.js.map +1 -1
- package/package.json +1 -1
- package/stackbone-sdk-0.1.0-alpha.6.tgz +0 -0
- package/stackbone-sdk-0.1.0-alpha.5.tgz +0 -0
package/CHANGELOG.md
CHANGED
package/index.cjs
CHANGED
|
@@ -8877,7 +8877,8 @@ var journalTerminalStatusSchema = zod.z.enum([
|
|
|
8877
8877
|
]);
|
|
8878
8878
|
var journalJobStatusSchema = zod.z.enum([
|
|
8879
8879
|
...journalTerminalStatusSchema.options,
|
|
8880
|
-
"running"
|
|
8880
|
+
"running",
|
|
8881
|
+
"lost"
|
|
8881
8882
|
]);
|
|
8882
8883
|
var jobStatusSchema = zod.z.enum([
|
|
8883
8884
|
...bullmqJobStatusSchema.options,
|
|
@@ -8979,6 +8980,27 @@ zod.z.object({
|
|
|
8979
8980
|
queue: zod.z.string(),
|
|
8980
8981
|
status: jobStatusSchema
|
|
8981
8982
|
});
|
|
8983
|
+
zod.z.object({
|
|
8984
|
+
items: zod.z.array(bullmqJobSchema)
|
|
8985
|
+
});
|
|
8986
|
+
zod.z.object({
|
|
8987
|
+
purged: zod.z.number().int().nonnegative()
|
|
8988
|
+
});
|
|
8989
|
+
zod.z.object({
|
|
8990
|
+
payload: jsonObject(),
|
|
8991
|
+
retries: zod.z.number().int().nonnegative().optional(),
|
|
8992
|
+
delay: zod.z.number().int().nonnegative().optional()
|
|
8993
|
+
});
|
|
8994
|
+
zod.z.object({
|
|
8995
|
+
message_id: zod.z.string(),
|
|
8996
|
+
queue: queueNameSchema
|
|
8997
|
+
});
|
|
8998
|
+
zod.z.object({
|
|
8999
|
+
name: queueNameSchema
|
|
9000
|
+
});
|
|
9001
|
+
zod.z.object({
|
|
9002
|
+
limit: zod.z.coerce.number().int().min(1).max(50).default(10)
|
|
9003
|
+
});
|
|
8982
9004
|
|
|
8983
9005
|
// ../shared/validators/src/lib/agents/queue-jobs.ts
|
|
8984
9006
|
var MAX_JOB_ATTEMPTS = 20;
|
|
@@ -9937,7 +9959,7 @@ var ApprovalFacade = class {
|
|
|
9937
9959
|
const fallback = onTimeoutToFallback(options.onTimeout);
|
|
9938
9960
|
const callbackUrl = options.onDecide;
|
|
9939
9961
|
try {
|
|
9940
|
-
const rows = await
|
|
9962
|
+
const rows = await this._getDatabase().runShared((db) => db`
|
|
9941
9963
|
INSERT INTO stackbone_platform.approvals (
|
|
9942
9964
|
topic, payload, callback_url, idempotency_key,
|
|
9943
9965
|
fallback, metadata, timeout_at
|
|
@@ -9956,7 +9978,7 @@ var ApprovalFacade = class {
|
|
|
9956
9978
|
RETURNING id, callback_url,
|
|
9957
9979
|
to_char(created_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') AS created_at,
|
|
9958
9980
|
to_char(timeout_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') AS timeout_at
|
|
9959
|
-
|
|
9981
|
+
`);
|
|
9960
9982
|
const row = rows[0];
|
|
9961
9983
|
if (!row) {
|
|
9962
9984
|
return err({
|
|
@@ -9991,13 +10013,13 @@ var ApprovalFacade = class {
|
|
|
9991
10013
|
const patch = reason ? {
|
|
9992
10014
|
cancelReason: reason
|
|
9993
10015
|
} : {};
|
|
9994
|
-
await
|
|
10016
|
+
await this._getDatabase().runShared((db) => db`
|
|
9995
10017
|
UPDATE stackbone_platform.approvals
|
|
9996
10018
|
SET status = 'cancelled',
|
|
9997
10019
|
decided_at = now(),
|
|
9998
10020
|
metadata = metadata || ${JSON.stringify(patch)}::jsonb
|
|
9999
10021
|
WHERE id = ${approvalId}::uuid AND status = 'pending'
|
|
10000
|
-
|
|
10022
|
+
`);
|
|
10001
10023
|
return ok(void 0);
|
|
10002
10024
|
} catch (cause) {
|
|
10003
10025
|
return err({
|
|
@@ -10017,14 +10039,14 @@ var ApprovalFacade = class {
|
|
|
10017
10039
|
const sql = this.sql();
|
|
10018
10040
|
if (sql.error) return err(sql.error);
|
|
10019
10041
|
try {
|
|
10020
|
-
const rows = await
|
|
10042
|
+
const rows = await this._getDatabase().runShared((db) => db`
|
|
10021
10043
|
SELECT id, topic, status, payload, metadata,
|
|
10022
10044
|
to_char(created_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') AS created_at,
|
|
10023
10045
|
to_char(timeout_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') AS timeout_at
|
|
10024
10046
|
FROM stackbone_platform.approvals
|
|
10025
10047
|
WHERE id = ${approvalId}::uuid
|
|
10026
10048
|
LIMIT 1
|
|
10027
|
-
|
|
10049
|
+
`);
|
|
10028
10050
|
const row = rows[0];
|
|
10029
10051
|
if (!row) {
|
|
10030
10052
|
return err({
|
|
@@ -10049,7 +10071,7 @@ var ApprovalFacade = class {
|
|
|
10049
10071
|
if (sql.error) return err(sql.error);
|
|
10050
10072
|
const limit = clampLimit(options.limit);
|
|
10051
10073
|
try {
|
|
10052
|
-
const rows = await
|
|
10074
|
+
const rows = await this._getDatabase().runShared((db) => db`
|
|
10053
10075
|
SELECT id, topic, status, payload, metadata,
|
|
10054
10076
|
to_char(created_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') AS created_at,
|
|
10055
10077
|
to_char(timeout_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') AS timeout_at
|
|
@@ -10058,7 +10080,7 @@ var ApprovalFacade = class {
|
|
|
10058
10080
|
AND (${options.topic ?? null}::text IS NULL OR topic = ${options.topic ?? null})
|
|
10059
10081
|
ORDER BY created_at DESC, id DESC
|
|
10060
10082
|
LIMIT ${limit}
|
|
10061
|
-
|
|
10083
|
+
`);
|
|
10062
10084
|
return ok({
|
|
10063
10085
|
items: rows.map((row) => toRecord(row))
|
|
10064
10086
|
});
|
|
@@ -10224,9 +10246,9 @@ var ConfigFacade = class {
|
|
|
10224
10246
|
const sql = this.sql();
|
|
10225
10247
|
if (sql.error) return err(sql.error);
|
|
10226
10248
|
try {
|
|
10227
|
-
const rows = await
|
|
10249
|
+
const rows = await this._getDatabase().runShared((db) => db`
|
|
10228
10250
|
SELECT payload FROM stackbone_platform.agent_config WHERE id = 1
|
|
10229
|
-
|
|
10251
|
+
`);
|
|
10230
10252
|
return ok(rows[0]?.payload ?? null);
|
|
10231
10253
|
} catch (cause) {
|
|
10232
10254
|
return err({
|
|
@@ -10300,6 +10322,10 @@ function isPoolTerminatedError(error) {
|
|
|
10300
10322
|
return typeof code === "string" && POOL_TERMINATED_ERROR_CODES.has(code);
|
|
10301
10323
|
}
|
|
10302
10324
|
__name(isPoolTerminatedError, "isPoolTerminatedError");
|
|
10325
|
+
function invalidatePoolHandle() {
|
|
10326
|
+
cachedHandle = null;
|
|
10327
|
+
}
|
|
10328
|
+
__name(invalidatePoolHandle, "invalidatePoolHandle");
|
|
10303
10329
|
async function runWithColdStartRetry(firstAttempt, retryAttempt) {
|
|
10304
10330
|
try {
|
|
10305
10331
|
return await firstAttempt();
|
|
@@ -10468,6 +10494,48 @@ var DatabaseModule = class {
|
|
|
10468
10494
|
// a half-baked tx. The contract gate fires before the first attempt.
|
|
10469
10495
|
transaction = /* @__PURE__ */ __name((...args) => withColdStartRetry(() => getDatabaseHandle(this._databaseUrl).transaction(...args), this._gate), "transaction");
|
|
10470
10496
|
/**
|
|
10497
|
+
* Cross-surface raw-SQL runner carrying the SAME cold-start resilience the
|
|
10498
|
+
* query-builder verbs above get. Sibling agent-local surfaces (`approval`,
|
|
10499
|
+
* `config`, `secrets`, `prompts`) that issue tagged-template queries over the
|
|
10500
|
+
* shared postgres-js `Sql` MUST execute them through this instead of caching
|
|
10501
|
+
* `shared().$client` once and calling it directly. Otherwise a dead pooled
|
|
10502
|
+
* socket — Fly Machines suspending the Machine between invokes, or a
|
|
10503
|
+
* WSL2/Docker localhost relay dropping an idle connection during a long LLM
|
|
10504
|
+
* step — surfaces as an unretried `CONNECTION_ENDED`/`ECONNRESET`. That is
|
|
10505
|
+
* exactly the asymmetry that let `client.approval.request` fail while the
|
|
10506
|
+
* `client.database.insert` right before it recovered.
|
|
10507
|
+
*
|
|
10508
|
+
* `fn` receives a FRESH `$client` on each attempt, so the single retry runs
|
|
10509
|
+
* against the rebuilt pool. Whole-operation granularity is replayed as a
|
|
10510
|
+
* unit — pass a multi-statement `sql.begin(...)` transaction or a helper that
|
|
10511
|
+
* fires several queries and the replay re-runs all of it; postgres-js never
|
|
10512
|
+
* commits a half-applied tx, so that is safe. SQLSTATE application errors
|
|
10513
|
+
* pass straight through without a retry. Like `shared()`/`raw()`, the
|
|
10514
|
+
* contract gate is intentionally NOT consulted here — gating surfaces gate at
|
|
10515
|
+
* their own call sites.
|
|
10516
|
+
*/
|
|
10517
|
+
runShared(fn) {
|
|
10518
|
+
return withColdStartRetry(() => fn(getDatabaseHandle(this._databaseUrl).$client));
|
|
10519
|
+
}
|
|
10520
|
+
/**
|
|
10521
|
+
* `Result`-shaped sibling of `runShared` for surfaces whose driver swallows
|
|
10522
|
+
* the dead-socket error into a returned `Result.err.cause` instead of
|
|
10523
|
+
* throwing it — today only `client.rag`, whose `RagPipeline` returns a
|
|
10524
|
+
* `Result` rather than throwing. `attempt` runs once; if it comes back with a
|
|
10525
|
+
* pool-terminated `cause`, the pool is rebuilt and `attempt` replays exactly
|
|
10526
|
+
* once, then its result (success or the fresh error) is returned verbatim.
|
|
10527
|
+
* The `Result` contract is preserved end to end: a still-dead socket on the
|
|
10528
|
+
* replay surfaces as the surface's own `Result.err`, never as a raw throw.
|
|
10529
|
+
*/
|
|
10530
|
+
async runSharedResult(attempt) {
|
|
10531
|
+
const first = await attempt();
|
|
10532
|
+
if (!first.error || !isPoolTerminatedError(first.error.cause)) return first;
|
|
10533
|
+
process.stderr.write(`[stackbone/sdk] database cold-start reconnect: rebuilding pool after ${first.error.cause.code ?? "unknown"}
|
|
10534
|
+
`);
|
|
10535
|
+
invalidatePoolHandle();
|
|
10536
|
+
return attempt();
|
|
10537
|
+
}
|
|
10538
|
+
/**
|
|
10471
10539
|
* Canonical accessor for the **shared-handles pattern**. Returns the
|
|
10472
10540
|
* process-wide Drizzle handle backing `client.database`. Cross-surface
|
|
10473
10541
|
* SDK consumers (RAG today, memory / queues tomorrow) call this — never
|
|
@@ -10569,12 +10637,12 @@ var PromptsFacade = class {
|
|
|
10569
10637
|
const sql = this.sql();
|
|
10570
10638
|
if (sql.error) return err(sql.error);
|
|
10571
10639
|
try {
|
|
10572
|
-
const head = await fetchHead(
|
|
10640
|
+
const head = await this._getDatabase().runShared((db) => fetchHead(db, key));
|
|
10573
10641
|
if (!head) {
|
|
10574
10642
|
return err(notFound(key));
|
|
10575
10643
|
}
|
|
10576
10644
|
if (options?.version !== void 0 && options.version !== head.current_version) {
|
|
10577
|
-
const content = await fetchVersionContent(
|
|
10645
|
+
const content = await this._getDatabase().runShared((db) => fetchVersionContent(db, key, options.version));
|
|
10578
10646
|
if (content === null) {
|
|
10579
10647
|
return err({
|
|
10580
10648
|
code: "prompts_not_found",
|
|
@@ -10625,7 +10693,7 @@ var PromptsFacade = class {
|
|
|
10625
10693
|
const sql = this.sql();
|
|
10626
10694
|
if (sql.error) return err(sql.error);
|
|
10627
10695
|
try {
|
|
10628
|
-
const rows = await
|
|
10696
|
+
const rows = await this._getDatabase().runShared((db) => db`
|
|
10629
10697
|
SELECT p.key, p.name, p.description, p.current_version, p.metadata,
|
|
10630
10698
|
p.created_at, p.updated_at, v.content
|
|
10631
10699
|
FROM stackbone_platform.prompts p
|
|
@@ -10634,7 +10702,7 @@ var PromptsFacade = class {
|
|
|
10634
10702
|
WHERE p.deleted_at IS NULL
|
|
10635
10703
|
ORDER BY p.key
|
|
10636
10704
|
LIMIT ${limit}
|
|
10637
|
-
|
|
10705
|
+
`);
|
|
10638
10706
|
return ok({
|
|
10639
10707
|
items: rows.map((row) => rowToPrompt(row, row.current_version, row.content))
|
|
10640
10708
|
});
|
|
@@ -10661,7 +10729,7 @@ var PromptsFacade = class {
|
|
|
10661
10729
|
if (sql.error) return err(sql.error);
|
|
10662
10730
|
const variables = extractVars(request.template);
|
|
10663
10731
|
try {
|
|
10664
|
-
const head = await
|
|
10732
|
+
const head = await this._getDatabase().runShared((db) => db.begin(async (tx) => {
|
|
10665
10733
|
await tx`
|
|
10666
10734
|
INSERT INTO stackbone_platform.prompts
|
|
10667
10735
|
(key, name, description, current_version, metadata)
|
|
@@ -10689,7 +10757,7 @@ var PromptsFacade = class {
|
|
|
10689
10757
|
WHERE p.key = ${request.key}
|
|
10690
10758
|
`;
|
|
10691
10759
|
return rows[0];
|
|
10692
|
-
});
|
|
10760
|
+
}));
|
|
10693
10761
|
if (!head) {
|
|
10694
10762
|
return err({
|
|
10695
10763
|
code: "prompts_unavailable",
|
|
@@ -10722,7 +10790,7 @@ var PromptsFacade = class {
|
|
|
10722
10790
|
const sql = this.sql();
|
|
10723
10791
|
if (sql.error) return err(sql.error);
|
|
10724
10792
|
try {
|
|
10725
|
-
const head = await
|
|
10793
|
+
const head = await this._getDatabase().runShared((db) => db.begin(async (tx) => {
|
|
10726
10794
|
await tx`SELECT pg_advisory_xact_lock(hashtext(${`prompts:${key}`}))`;
|
|
10727
10795
|
const existing = await tx`
|
|
10728
10796
|
SELECT p.key, p.name, p.description, p.current_version, p.metadata,
|
|
@@ -10766,7 +10834,7 @@ var PromptsFacade = class {
|
|
|
10766
10834
|
WHERE p.key = ${key}
|
|
10767
10835
|
`;
|
|
10768
10836
|
return rows[0] ?? null;
|
|
10769
|
-
});
|
|
10837
|
+
}));
|
|
10770
10838
|
if (head === null) {
|
|
10771
10839
|
return err(notFound(key));
|
|
10772
10840
|
}
|
|
@@ -10781,12 +10849,12 @@ var PromptsFacade = class {
|
|
|
10781
10849
|
const sql = this.sql();
|
|
10782
10850
|
if (sql.error) return err(sql.error);
|
|
10783
10851
|
try {
|
|
10784
|
-
const rows = await
|
|
10852
|
+
const rows = await this._getDatabase().runShared((db) => db`
|
|
10785
10853
|
UPDATE stackbone_platform.prompts
|
|
10786
10854
|
SET deleted_at = now(), updated_at = now()
|
|
10787
10855
|
WHERE key = ${key} AND deleted_at IS NULL
|
|
10788
10856
|
RETURNING key
|
|
10789
|
-
|
|
10857
|
+
`);
|
|
10790
10858
|
const deleted = rows.length;
|
|
10791
10859
|
if (deleted === 0) {
|
|
10792
10860
|
return err(notFound(key));
|
|
@@ -11870,8 +11938,10 @@ var RagModule = class {
|
|
|
11870
11938
|
const sql = this.sql();
|
|
11871
11939
|
if (sql.error) return err(sql.error);
|
|
11872
11940
|
try {
|
|
11873
|
-
await
|
|
11874
|
-
|
|
11941
|
+
await this._getDatabase().runShared(async (db) => {
|
|
11942
|
+
await db`DROP TABLE IF EXISTS rag_chunks`;
|
|
11943
|
+
await db`DROP TABLE IF EXISTS _rag_meta`;
|
|
11944
|
+
});
|
|
11875
11945
|
return ok(void 0);
|
|
11876
11946
|
} catch (cause) {
|
|
11877
11947
|
return err(toRagError(cause, "Reset failed"));
|
|
@@ -11921,13 +11991,15 @@ var RagModule = class {
|
|
|
11921
11991
|
}
|
|
11922
11992
|
}
|
|
11923
11993
|
async withPipeline(embedder, run) {
|
|
11924
|
-
|
|
11925
|
-
|
|
11926
|
-
|
|
11927
|
-
embedder
|
|
11928
|
-
|
|
11994
|
+
return this._getDatabase().runSharedResult(async () => {
|
|
11995
|
+
const pipeline = new RagPipeline({
|
|
11996
|
+
sqlProvider: /* @__PURE__ */ __name(() => this.sql(), "sqlProvider"),
|
|
11997
|
+
...embedder && {
|
|
11998
|
+
embedder
|
|
11999
|
+
}
|
|
12000
|
+
});
|
|
12001
|
+
return await run(pipeline);
|
|
11929
12002
|
});
|
|
11930
|
-
return await run(pipeline);
|
|
11931
12003
|
}
|
|
11932
12004
|
};
|
|
11933
12005
|
function countChunks(request) {
|
|
@@ -15810,12 +15882,12 @@ var SecretsFacade = class {
|
|
|
15810
15882
|
if (sql.error) return err(sql.error);
|
|
15811
15883
|
let rows;
|
|
15812
15884
|
try {
|
|
15813
|
-
rows = await
|
|
15885
|
+
rows = await this._getDatabase().runShared((db) => db`
|
|
15814
15886
|
SELECT version, nonce, ciphertext
|
|
15815
15887
|
FROM stackbone_platform.secrets
|
|
15816
15888
|
WHERE name = ${name}
|
|
15817
15889
|
LIMIT 1
|
|
15818
|
-
|
|
15890
|
+
`);
|
|
15819
15891
|
} catch (cause) {
|
|
15820
15892
|
return err({
|
|
15821
15893
|
code: "secrets_unavailable",
|
|
@@ -15861,11 +15933,11 @@ var SecretsFacade = class {
|
|
|
15861
15933
|
if (sql.error) return err(sql.error);
|
|
15862
15934
|
let rows;
|
|
15863
15935
|
try {
|
|
15864
|
-
rows = await
|
|
15936
|
+
rows = await this._getDatabase().runShared((db) => db`
|
|
15865
15937
|
SELECT name, version, nonce, ciphertext
|
|
15866
15938
|
FROM stackbone_platform.secrets
|
|
15867
15939
|
WHERE name = ANY(${names})
|
|
15868
|
-
|
|
15940
|
+
`);
|
|
15869
15941
|
} catch (cause) {
|
|
15870
15942
|
return err({
|
|
15871
15943
|
code: "secrets_unavailable",
|
|
@@ -17274,9 +17346,7 @@ var STORED_TO_SDK_ENV = {
|
|
|
17274
17346
|
S3_REGION: "STACKBONE_S3_REGION",
|
|
17275
17347
|
// OpenRouter (`client.ai`) — identity.
|
|
17276
17348
|
OPENROUTER_API_KEY: "OPENROUTER_API_KEY",
|
|
17277
|
-
OPENROUTER_BASE_URL: "OPENROUTER_BASE_URL"
|
|
17278
|
-
// Axiom (observability) — identity.
|
|
17279
|
-
AXIOM_TOKEN: "AXIOM_TOKEN"
|
|
17349
|
+
OPENROUTER_BASE_URL: "OPENROUTER_BASE_URL"
|
|
17280
17350
|
};
|
|
17281
17351
|
function rehydrateSystemSecretsRows(env, rows, cipher, databaseUrl) {
|
|
17282
17352
|
const applied = [];
|