@stackbone/sdk 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +693 -0
- package/db/index.cjs +21 -0
- package/db/index.cjs.map +1 -0
- package/db/index.d.cts +3 -0
- package/db/index.d.ts +3 -0
- package/db/index.js +4 -0
- package/db/index.js.map +1 -0
- package/db/testing/index.cjs +83 -0
- package/db/testing/index.cjs.map +1 -0
- package/db/testing/index.d.cts +48 -0
- package/db/testing/index.d.ts +48 -0
- package/db/testing/index.js +77 -0
- package/db/testing/index.js.map +1 -0
- package/index.cjs +19977 -0
- package/index.cjs.map +1 -0
- package/index.d.cts +1325 -0
- package/index.d.ts +1325 -0
- package/index.js +19961 -0
- package/index.js.map +1 -0
- package/package.json +108 -0
- package/queues/types.cjs +4 -0
- package/queues/types.cjs.map +1 -0
- package/queues/types.d.cts +14 -0
- package/queues/types.d.ts +14 -0
- package/queues/types.js +3 -0
- package/queues/types.js.map +1 -0
- package/rag/migrations/index.cjs +71 -0
- package/rag/migrations/index.cjs.map +1 -0
- package/rag/migrations/index.d.cts +29 -0
- package/rag/migrations/index.d.ts +29 -0
- package/rag/migrations/index.js +66 -0
- package/rag/migrations/index.js.map +1 -0
- package/rag/schema.cjs +124 -0
- package/rag/schema.cjs.map +1 -0
- package/rag/schema.d.cts +446 -0
- package/rag/schema.d.ts +446 -0
- package/rag/schema.js +96 -0
- package/rag/schema.js.map +1 -0
- package/stackbone-sdk-0.1.0-alpha.0.tgz +0 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,1325 @@
|
|
|
1
|
+
import { ContractResponse } from '@stackbone/validators';
|
|
2
|
+
import OpenAI from 'openai';
|
|
3
|
+
import { ChatCompletionCreateParamsStreaming, ChatCompletionChunk, ChatCompletionCreateParamsNonStreaming, ChatCompletion, EmbeddingCreateParams, CreateEmbeddingResponse, ChatCompletionMessageParam } from 'openai/resources';
|
|
4
|
+
import { Stream } from 'openai/streaming';
|
|
5
|
+
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
6
|
+
import { Sql } from 'postgres';
|
|
7
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Optional overrides accepted by `createClient`. All fields are optional;
|
|
11
|
+
* modules fall back to the corresponding upstream env var on first access.
|
|
12
|
+
*/
|
|
13
|
+
interface ClientConfig {
|
|
14
|
+
/** Ed25519 JWT signed by the control plane. Falls back to `STACKBONE_AGENT_JWT`. */
|
|
15
|
+
agentJwt?: string;
|
|
16
|
+
/** Stackbone control plane base URL used by the facade HttpClient. Falls back to `STACKBONE_API_URL`. */
|
|
17
|
+
stackboneApiUrl?: string;
|
|
18
|
+
/** Stable agent identifier injected at provisioning. Falls back to `STACKBONE_AGENT_ID`. Used as the multi-tenant key prefix in `client.storage`. */
|
|
19
|
+
agentId?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Postgres connection string consumed by `client.rag` and the platform
|
|
22
|
+
* observability exporter. Falls back to `DATABASE_URL`. Note: `client.database`
|
|
23
|
+
* uses `STACKBONE_POSTGRES_URL` instead — the two env vars are intentionally
|
|
24
|
+
* different so that the SDK's own DB pool stays decoupled from the legacy
|
|
25
|
+
* `DATABASE_URL` consumers until `feature 30` consolidates them.
|
|
26
|
+
*/
|
|
27
|
+
databaseUrl?: string;
|
|
28
|
+
openrouterKey?: string;
|
|
29
|
+
openrouterBaseUrl?: string;
|
|
30
|
+
qstashToken?: string;
|
|
31
|
+
qstashCurrentSigningKey?: string;
|
|
32
|
+
qstashNextSigningKey?: string;
|
|
33
|
+
llamaParseApiKey?: string;
|
|
34
|
+
/** mem0 API key for the long-term memory backend (`client.memory`). Falls back to `MEM0_API_KEY`. */
|
|
35
|
+
mem0ApiKey?: string;
|
|
36
|
+
/** mem0 API base URL. Falls back to `MEM0_BASE_URL` (defaults to mem0 cloud when unset). */
|
|
37
|
+
mem0BaseUrl?: string;
|
|
38
|
+
/** HMAC key the control plane uses to sign approval-decision callbacks. Falls back to `STACKBONE_APPROVAL_SIGNING_KEY`. */
|
|
39
|
+
approvalSigningKey?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Identifies the install the agent runs inside. Sent as the
|
|
42
|
+
* `X-Stackbone-Installation-Id` header when the SDK talks to the control
|
|
43
|
+
* plane. Falls back to `STACKBONE_INSTALLATION_ID`.
|
|
44
|
+
* TODO(studio-v1): remove once `STACKBONE_AGENT_JWT` carries the install id
|
|
45
|
+
* and `apps/api` derives it from the bearer instead of an explicit header.
|
|
46
|
+
*/
|
|
47
|
+
installationId?: string;
|
|
48
|
+
s3?: {
|
|
49
|
+
/** Falls back to `AWS_ACCESS_KEY_ID`. */
|
|
50
|
+
accessKeyId?: string;
|
|
51
|
+
/** Falls back to `AWS_SECRET_ACCESS_KEY`. */
|
|
52
|
+
secretAccessKey?: string;
|
|
53
|
+
/** Falls back to `S3_ENDPOINT`. */
|
|
54
|
+
endpoint?: string;
|
|
55
|
+
/** Physical R2/S3 bucket scoped to the agent. Falls back to `S3_BUCKET`. */
|
|
56
|
+
bucket?: string;
|
|
57
|
+
};
|
|
58
|
+
otel?: {
|
|
59
|
+
exporterOtlpEndpoint?: string;
|
|
60
|
+
resourceAttributes?: string;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* RAG-related defaults parsed from `agent.yaml.rag` by the CLI/orchestrator
|
|
64
|
+
* and forwarded here. The SDK never reads `agent.yaml` itself — keeping
|
|
65
|
+
* filesystem ownership in the CLI. Defaults follow ADR
|
|
66
|
+
* `2026-05-10-rag-consolidation-on-client-database` (D2/D6).
|
|
67
|
+
*/
|
|
68
|
+
rag?: {
|
|
69
|
+
/**
|
|
70
|
+
* Embedding model used by `client.rag.ingest`/`retrieve` when the caller
|
|
71
|
+
* omits `model`. Defaults to `openai/text-embedding-3-small`.
|
|
72
|
+
*/
|
|
73
|
+
embeddingModel?: string;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Creator-side floor on the negotiated Stackbone Agent Protocol contract
|
|
77
|
+
* version. Sourced from `agent.yaml.protocol.required` by the
|
|
78
|
+
* CLI/orchestrator (the SDK never reads `agent.yaml` itself). When set and
|
|
79
|
+
* the datapath's negotiated `contract.version` is below this value, every
|
|
80
|
+
* gated module call returns `SdkError('contract_version_unsupported',
|
|
81
|
+
* { detected, required })` — independent of per-module capability gating.
|
|
82
|
+
* When omitted, the SDK uses `MIN_SUPPORTED_CONTRACT_VERSION` as the
|
|
83
|
+
* implicit floor (i.e. behaviour matches slice F5).
|
|
84
|
+
*/
|
|
85
|
+
protocolRequired?: number;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* `env` is a live reference to `process.env` (not a snapshot) so tests that
|
|
89
|
+
* mutate the environment between `createClient()` and the first module access
|
|
90
|
+
* still observe the new values via the lazy initialisers.
|
|
91
|
+
*/
|
|
92
|
+
interface ResolvedConfig {
|
|
93
|
+
config: Readonly<ClientConfig>;
|
|
94
|
+
env: NodeJS.ProcessEnv;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Uniform error envelope returned by every SDK method. `cause` and `meta` are
|
|
99
|
+
* optional escape hatches so wrappers can attach upstream errors / context
|
|
100
|
+
* without breaking the public shape.
|
|
101
|
+
*/
|
|
102
|
+
interface SdkError {
|
|
103
|
+
code: string;
|
|
104
|
+
message: string;
|
|
105
|
+
cause?: unknown;
|
|
106
|
+
meta?: Record<string, unknown>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Discriminated result the entire SDK returns. Narrowing on `result.error`
|
|
110
|
+
* automatically refines `result.data` to `T`.
|
|
111
|
+
*/
|
|
112
|
+
type Result<T> = {
|
|
113
|
+
data: T;
|
|
114
|
+
error: null;
|
|
115
|
+
} | {
|
|
116
|
+
data: null;
|
|
117
|
+
error: SdkError;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Async predicate every gated SDK module awaits before forwarding to its
|
|
122
|
+
* underlying implementation. Returns ok when the negotiated contract clears
|
|
123
|
+
* the module's gate (or the escape hatch suppresses a gating error); returns
|
|
124
|
+
* an error envelope otherwise — the caller propagates it back as the public
|
|
125
|
+
* `Result<T>` of the method.
|
|
126
|
+
*
|
|
127
|
+
* Test seam — every gated module exposes an optional `gate` constructor
|
|
128
|
+
* argument that defaults to `createModuleGate(<id>, resolved)`. Specs inject
|
|
129
|
+
* a stub returning a synthetic `Result<undefined>` to exercise the gating
|
|
130
|
+
* paths (ok / `contract_version_unsupported` / `capability_unavailable` /
|
|
131
|
+
* `contract_unreachable`) without driving a real handshake.
|
|
132
|
+
*/
|
|
133
|
+
type ModuleGate = () => Promise<Result<undefined>>;
|
|
134
|
+
|
|
135
|
+
/** Subset of `RequestInit['body']` we serialize without modification. */
|
|
136
|
+
type SerializedBody = NonNullable<RequestInit['body']>;
|
|
137
|
+
interface RequestOptions$1 extends Omit<RequestInit, 'body' | 'signal'> {
|
|
138
|
+
params?: Record<string, string>;
|
|
139
|
+
body?: SerializedBody | Record<string, unknown> | unknown[] | null;
|
|
140
|
+
signal?: AbortSignal;
|
|
141
|
+
/** Allow retrying non-idempotent requests (POST, PATCH). Off by default to prevent duplicate writes. */
|
|
142
|
+
idempotent?: boolean;
|
|
143
|
+
}
|
|
144
|
+
interface HttpClientOptions {
|
|
145
|
+
/** Default 30_000. Set to 0 to disable. */
|
|
146
|
+
timeout?: number;
|
|
147
|
+
/** Default 3. Set to 0 to disable. */
|
|
148
|
+
retryCount?: number;
|
|
149
|
+
/** Initial backoff in ms; doubles each attempt with ±15% jitter. Default 500. */
|
|
150
|
+
retryDelay?: number;
|
|
151
|
+
/** Override the global fetch (useful for tests). */
|
|
152
|
+
fetch?: typeof fetch;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Shared HTTP client used by the control-plane facades (approval, secrets,
|
|
156
|
+
* connections, config, events). Wraps `fetch` with timeout, exponential
|
|
157
|
+
* backoff with jitter, idempotent-only retries, and a uniform Result
|
|
158
|
+
* envelope so facades never throw at the SDK boundary.
|
|
159
|
+
*
|
|
160
|
+
* Reads `STACKBONE_API_URL` and `STACKBONE_AGENT_JWT` lazily on every request so
|
|
161
|
+
* env-var rotation is picked up without restarting the client.
|
|
162
|
+
*/
|
|
163
|
+
declare class HttpClient {
|
|
164
|
+
private readonly resolved;
|
|
165
|
+
private readonly timeout;
|
|
166
|
+
private readonly retryCount;
|
|
167
|
+
private readonly retryDelay;
|
|
168
|
+
private readonly fetchImpl;
|
|
169
|
+
constructor(resolved: ResolvedConfig, options?: HttpClientOptions);
|
|
170
|
+
get<T>(path: string, options?: RequestOptions$1): Promise<Result<T>>;
|
|
171
|
+
post<T>(path: string, body?: RequestOptions$1['body'], options?: RequestOptions$1): Promise<Result<T>>;
|
|
172
|
+
put<T>(path: string, body?: RequestOptions$1['body'], options?: RequestOptions$1): Promise<Result<T>>;
|
|
173
|
+
patch<T>(path: string, body?: RequestOptions$1['body'], options?: RequestOptions$1): Promise<Result<T>>;
|
|
174
|
+
delete<T>(path: string, options?: RequestOptions$1): Promise<Result<T>>;
|
|
175
|
+
request<T>(method: string, path: string, options?: RequestOptions$1): Promise<Result<T>>;
|
|
176
|
+
private computeBackoff;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
interface ApprovalToolSpec<I, O> {
|
|
180
|
+
name: string;
|
|
181
|
+
description: string;
|
|
182
|
+
parameters: Record<string, unknown>;
|
|
183
|
+
needsApproval?: boolean | ((input: I) => boolean | Promise<boolean>);
|
|
184
|
+
/**
|
|
185
|
+
* Maps the LLM input to the approval request fields. `topic` and `payload`
|
|
186
|
+
* default to the tool name and the raw input respectively when omitted;
|
|
187
|
+
* `onDecide` must always be supplied so the control plane knows where to
|
|
188
|
+
* deliver the eventual decision.
|
|
189
|
+
*/
|
|
190
|
+
toRequest: (input: I) => Omit<ApprovalRequestOptions<I>, 'payload' | 'topic'> & Partial<Pick<ApprovalRequestOptions<I>, 'payload' | 'topic'>>;
|
|
191
|
+
execute: (input: I) => Promise<O> | O;
|
|
192
|
+
}
|
|
193
|
+
interface OpenAIToolSpec {
|
|
194
|
+
type: 'function';
|
|
195
|
+
function: {
|
|
196
|
+
name: string;
|
|
197
|
+
description: string;
|
|
198
|
+
parameters: Record<string, unknown>;
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
type ToolInvokeResult<O> = {
|
|
202
|
+
status: 'pending';
|
|
203
|
+
approvalId: string;
|
|
204
|
+
expiresAt: string;
|
|
205
|
+
} | {
|
|
206
|
+
status: 'ok';
|
|
207
|
+
result: O;
|
|
208
|
+
};
|
|
209
|
+
interface ApprovalTool<I, O> {
|
|
210
|
+
name: string;
|
|
211
|
+
description: string;
|
|
212
|
+
parameters: Record<string, unknown>;
|
|
213
|
+
openaiSpec(): OpenAIToolSpec;
|
|
214
|
+
invoke(input: I): Promise<Result<ToolInvokeResult<O>>>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
interface VerifyOptions {
|
|
218
|
+
/** Override the signing key resolved from `STACKBONE_APPROVAL_SIGNING_KEY` / `approvalSigningKey`. */
|
|
219
|
+
signingKey?: string;
|
|
220
|
+
/** Reject signatures whose timestamp is older than this (seconds). Default 300. */
|
|
221
|
+
toleranceSeconds?: number;
|
|
222
|
+
/** Inject a clock for tests. Defaults to `Date.now`. */
|
|
223
|
+
now?: () => number;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
type ApprovalTopic = string;
|
|
227
|
+
declare const DECISION_STATUSES: readonly ["approved", "rejected", "timed_out", "cancelled"];
|
|
228
|
+
type DecisionStatus = (typeof DECISION_STATUSES)[number];
|
|
229
|
+
type ApprovalStatus = 'pending' | DecisionStatus;
|
|
230
|
+
type Decision<T = unknown> = {
|
|
231
|
+
status: 'approved' | 'rejected';
|
|
232
|
+
payload: T;
|
|
233
|
+
approver: ApproverInfo;
|
|
234
|
+
decidedAt: string;
|
|
235
|
+
reason?: string;
|
|
236
|
+
} | {
|
|
237
|
+
status: 'timed_out';
|
|
238
|
+
decidedAt: string;
|
|
239
|
+
} | {
|
|
240
|
+
status: 'cancelled';
|
|
241
|
+
decidedAt: string;
|
|
242
|
+
reason?: string;
|
|
243
|
+
};
|
|
244
|
+
interface ApproverInfo {
|
|
245
|
+
id: string;
|
|
246
|
+
email: string;
|
|
247
|
+
name?: string;
|
|
248
|
+
}
|
|
249
|
+
interface ApprovalRequestOptions<T = unknown> {
|
|
250
|
+
topic: ApprovalTopic;
|
|
251
|
+
payload: T;
|
|
252
|
+
title?: string;
|
|
253
|
+
description?: string;
|
|
254
|
+
/** Path on the agent the control plane will POST the decision to (resolved against the agent's public URL server-side). */
|
|
255
|
+
onDecide: string;
|
|
256
|
+
/** ISO 8601 duration (`'24h'`) or milliseconds. Default 24h. */
|
|
257
|
+
timeout?: string | number;
|
|
258
|
+
onTimeout?: 'reject' | 'approve' | 'ignore';
|
|
259
|
+
approver?: string;
|
|
260
|
+
/** Same `(topic, idempotencyKey)` returns the same `approvalId` instead of creating a new one. */
|
|
261
|
+
idempotencyKey?: string;
|
|
262
|
+
metadata?: Record<string, unknown>;
|
|
263
|
+
}
|
|
264
|
+
interface ApprovalRequest {
|
|
265
|
+
approvalId: string;
|
|
266
|
+
status: 'pending';
|
|
267
|
+
callbackUrl: string;
|
|
268
|
+
expiresAt: string;
|
|
269
|
+
}
|
|
270
|
+
interface ApprovalRecord<T = unknown> {
|
|
271
|
+
approvalId: string;
|
|
272
|
+
topic: ApprovalTopic;
|
|
273
|
+
status: ApprovalStatus;
|
|
274
|
+
payload: T;
|
|
275
|
+
decision?: Decision<T>;
|
|
276
|
+
createdAt: string;
|
|
277
|
+
expiresAt: string;
|
|
278
|
+
metadata?: Record<string, unknown>;
|
|
279
|
+
}
|
|
280
|
+
interface ApprovalListOptions {
|
|
281
|
+
status?: ApprovalStatus;
|
|
282
|
+
topic?: ApprovalTopic;
|
|
283
|
+
cursor?: string;
|
|
284
|
+
/** 1..100. Default 50. */
|
|
285
|
+
limit?: number;
|
|
286
|
+
}
|
|
287
|
+
interface ApprovalListResult<T = unknown> {
|
|
288
|
+
items: ApprovalRecord<T>[];
|
|
289
|
+
nextCursor?: string;
|
|
290
|
+
}
|
|
291
|
+
declare class ApprovalFacade {
|
|
292
|
+
private readonly _resolved;
|
|
293
|
+
private readonly _http;
|
|
294
|
+
private readonly _gate;
|
|
295
|
+
constructor(_resolved: ResolvedConfig, _http: HttpClient,
|
|
296
|
+
/** Test seam — see `ModuleGate`. Defaults to the lazy contract gate. */
|
|
297
|
+
gate?: ModuleGate);
|
|
298
|
+
request<T = unknown>(options: ApprovalRequestOptions<T>): Promise<Result<ApprovalRequest>>;
|
|
299
|
+
cancel(approvalId: string, reason?: string): Promise<Result<void>>;
|
|
300
|
+
get<T = unknown>(approvalId: string): Promise<Result<ApprovalRecord<T>>>;
|
|
301
|
+
list<T = unknown>(options?: ApprovalListOptions): Promise<Result<ApprovalListResult<T>>>;
|
|
302
|
+
/**
|
|
303
|
+
* Local crypto verification — does not touch the datapath, so it is NOT
|
|
304
|
+
* gated by the contract handshake. Auditing rule: a method gates iff it
|
|
305
|
+
* issues an HTTP request to the configured baseUrl.
|
|
306
|
+
*/
|
|
307
|
+
verify<T = unknown>(request: Request, options?: VerifyOptions): Promise<Result<Decision<T>>>;
|
|
308
|
+
/**
|
|
309
|
+
* Pure factory — returns an `ApprovalTool` whose `invoke()` ultimately
|
|
310
|
+
* calls back into `ApprovalFacade.request`, so the gate fires there. Not
|
|
311
|
+
* gated here.
|
|
312
|
+
*/
|
|
313
|
+
tool<I, O>(spec: ApprovalToolSpec<I, O>): ApprovalTool<I, O>;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
declare class ConfigFacade {
|
|
317
|
+
private readonly _http;
|
|
318
|
+
private readonly _gate;
|
|
319
|
+
constructor(resolved: ResolvedConfig, _http: HttpClient,
|
|
320
|
+
/** Test seam — see `ModuleGate`. Defaults to the lazy contract gate. */
|
|
321
|
+
gate?: ModuleGate);
|
|
322
|
+
get<T = unknown>(key: string): Promise<Result<T>>;
|
|
323
|
+
/**
|
|
324
|
+
* Keys absent from the agent's config come back as omissions in the
|
|
325
|
+
* response — the returned map only contains entries the control plane
|
|
326
|
+
* actually has, so callers must access fields with `?.` (the return type
|
|
327
|
+
* is `Partial<T>`).
|
|
328
|
+
*/
|
|
329
|
+
getMany<T extends Record<string, unknown> = Record<string, unknown>>(keys: string[]): Promise<Result<Partial<T>>>;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** OAuth connections (Notion, GDrive, Slack…). */
|
|
333
|
+
declare class ConnectionsFacade {
|
|
334
|
+
private readonly _resolved;
|
|
335
|
+
private readonly _http;
|
|
336
|
+
constructor(_resolved: ResolvedConfig, _http: HttpClient);
|
|
337
|
+
list(): Promise<Result<readonly never[]>>;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** Emit events to the workspace event bus. */
|
|
341
|
+
declare class EventsFacade {
|
|
342
|
+
private readonly _http;
|
|
343
|
+
private readonly _gate;
|
|
344
|
+
constructor(resolved: ResolvedConfig, _http: HttpClient,
|
|
345
|
+
/** Test seam — see `ModuleGate`. Defaults to the lazy contract gate. */
|
|
346
|
+
gate?: ModuleGate);
|
|
347
|
+
emit(_name: string, _payload: unknown): Promise<Result<void>>;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* A prompt managed by the Stackbone control plane. Templates are plain strings
|
|
352
|
+
* with Mustache-style `{{var}}` placeholders — no conditionals or loops.
|
|
353
|
+
*/
|
|
354
|
+
interface Prompt {
|
|
355
|
+
name: string;
|
|
356
|
+
template: string;
|
|
357
|
+
/** Monotonically increasing per `name`. The first `create` produces version `1`. */
|
|
358
|
+
version: number;
|
|
359
|
+
/** Variable names parsed from the template. */
|
|
360
|
+
variables?: readonly string[];
|
|
361
|
+
metadata?: Record<string, unknown>;
|
|
362
|
+
/** ISO 8601 UTC timestamp. */
|
|
363
|
+
createdAt: string;
|
|
364
|
+
updatedAt: string;
|
|
365
|
+
}
|
|
366
|
+
interface GetPromptOptions {
|
|
367
|
+
/** Pin a specific version. Omitted -> latest. */
|
|
368
|
+
version?: number;
|
|
369
|
+
}
|
|
370
|
+
interface ListPromptsOptions {
|
|
371
|
+
/** 1..100. Default 50. */
|
|
372
|
+
limit?: number;
|
|
373
|
+
cursor?: string;
|
|
374
|
+
}
|
|
375
|
+
interface ListPromptsResult {
|
|
376
|
+
/** Latest version of each prompt. */
|
|
377
|
+
items: readonly Prompt[];
|
|
378
|
+
nextCursor?: string;
|
|
379
|
+
}
|
|
380
|
+
interface CreatePromptRequest {
|
|
381
|
+
name: string;
|
|
382
|
+
template: string;
|
|
383
|
+
metadata?: Record<string, unknown>;
|
|
384
|
+
}
|
|
385
|
+
interface UpdatePromptOptions {
|
|
386
|
+
/** New template. Bumps `version` by one. */
|
|
387
|
+
template?: string;
|
|
388
|
+
/** Shallow-merged onto the existing metadata. */
|
|
389
|
+
metadata?: Record<string, unknown>;
|
|
390
|
+
}
|
|
391
|
+
interface DeletePromptOptions {
|
|
392
|
+
/** Delete a specific version. Omitted -> delete every version under `name`. */
|
|
393
|
+
version?: number;
|
|
394
|
+
}
|
|
395
|
+
interface DeletePromptResult {
|
|
396
|
+
name: string;
|
|
397
|
+
/** Number of versions actually removed. */
|
|
398
|
+
deleted: number;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* `client.prompts` — managed prompts for the agent. Prompts live outside the
|
|
402
|
+
* code so creators can edit, version and A/B test them without rebuilding the
|
|
403
|
+
* container. The first iteration is a scaffolding placeholder: every method
|
|
404
|
+
* returns `not_implemented`. The real backend will be the Stackbone control
|
|
405
|
+
* plane and the public surface defined here is the contract callers can
|
|
406
|
+
* already type against.
|
|
407
|
+
*/
|
|
408
|
+
declare class PromptsFacade {
|
|
409
|
+
private readonly _http;
|
|
410
|
+
constructor(_resolved: ResolvedConfig, _http: HttpClient);
|
|
411
|
+
get(_name: string, _options?: GetPromptOptions): Promise<Result<Prompt>>;
|
|
412
|
+
compile(_name: string, _variables: Record<string, unknown>, _options?: GetPromptOptions): Promise<Result<string>>;
|
|
413
|
+
list(_options?: ListPromptsOptions): Promise<Result<ListPromptsResult>>;
|
|
414
|
+
create(_request: CreatePromptRequest): Promise<Result<Prompt>>;
|
|
415
|
+
update(_name: string, _options: UpdatePromptOptions): Promise<Result<Prompt>>;
|
|
416
|
+
delete(_name: string, _options?: DeletePromptOptions): Promise<Result<DeletePromptResult>>;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
declare class SecretsFacade {
|
|
420
|
+
private readonly _http;
|
|
421
|
+
private readonly _gate;
|
|
422
|
+
constructor(resolved: ResolvedConfig, _http: HttpClient,
|
|
423
|
+
/** Test seam — see `ModuleGate`. Defaults to the lazy contract gate. */
|
|
424
|
+
gate?: ModuleGate);
|
|
425
|
+
get(name: string): Promise<Result<string>>;
|
|
426
|
+
/**
|
|
427
|
+
* Names absent from the workspace come back as omissions in the response —
|
|
428
|
+
* the returned map only contains entries the control plane actually has.
|
|
429
|
+
* Callers that need "all-or-nothing" semantics should diff the keys.
|
|
430
|
+
*/
|
|
431
|
+
getMany(names: string[]): Promise<Result<Record<string, string>>>;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Public surface behind `client.ai`. Wraps the official `openai` SDK with a
|
|
436
|
+
* `baseURL` override pointing to OpenRouter, so 300+ models are reachable
|
|
437
|
+
* with a single, OpenAI-compatible API.
|
|
438
|
+
*
|
|
439
|
+
* Lazy: the underlying `OpenAI` client is built on the first method call
|
|
440
|
+
* (or the first time a sub-namespace is touched) so env vars mutated after
|
|
441
|
+
* `createClient()` are still picked up — same pattern as `DatabaseModule`.
|
|
442
|
+
*
|
|
443
|
+
* Error model: every method returns `Result<T>`. Upstream `APIError`s are
|
|
444
|
+
* mapped to `SdkError` with stable `ai_*` codes. For streaming, the
|
|
445
|
+
* `Result` envelope only covers connection establishment; once the stream
|
|
446
|
+
* is open, mid-flight errors propagate through the iterator — callers must
|
|
447
|
+
* wrap their `for await` loop in `try/catch`. Aborts via `signal.abort()`
|
|
448
|
+
* surface as `ai_aborted` in non-streaming requests; in streaming, the
|
|
449
|
+
* iterator simply terminates (the upstream SDK swallows the abort).
|
|
450
|
+
*
|
|
451
|
+
* Test override: pass `clientOverride` to inject a pre-built `OpenAI`
|
|
452
|
+
* instance (or a stand-in) instead of letting the module build one. The
|
|
453
|
+
* override flows to all four namespaces — `models.list()` included.
|
|
454
|
+
*/
|
|
455
|
+
declare class AiModule {
|
|
456
|
+
private readonly _resolved;
|
|
457
|
+
private _openai;
|
|
458
|
+
private _chat;
|
|
459
|
+
private _embeddings;
|
|
460
|
+
private _images;
|
|
461
|
+
private _models;
|
|
462
|
+
private readonly _gate;
|
|
463
|
+
constructor(_resolved: ResolvedConfig, clientOverride?: OpenAI,
|
|
464
|
+
/** Test seam — see `ModuleGate`. Defaults to the lazy contract gate. */
|
|
465
|
+
gate?: ModuleGate);
|
|
466
|
+
get chat(): {
|
|
467
|
+
completions: ChatCompletionsNamespace;
|
|
468
|
+
};
|
|
469
|
+
get embeddings(): EmbeddingsNamespace;
|
|
470
|
+
get images(): ImagesNamespace;
|
|
471
|
+
get models(): ModelsNamespace;
|
|
472
|
+
private client;
|
|
473
|
+
}
|
|
474
|
+
declare class ChatCompletionsNamespace {
|
|
475
|
+
private readonly _getClient;
|
|
476
|
+
private readonly _gate;
|
|
477
|
+
constructor(_getClient: () => Result<OpenAI>, _gate: ModuleGate);
|
|
478
|
+
create(params: ChatCompletionCreateParamsStreaming, options?: RequestOptions): Promise<Result<Stream<ChatCompletionChunk>>>;
|
|
479
|
+
create(params: ChatCompletionCreateParamsNonStreaming, options?: RequestOptions): Promise<Result<ChatCompletion>>;
|
|
480
|
+
}
|
|
481
|
+
declare class EmbeddingsNamespace {
|
|
482
|
+
private readonly _getClient;
|
|
483
|
+
private readonly _gate;
|
|
484
|
+
constructor(_getClient: () => Result<OpenAI>, _gate: ModuleGate);
|
|
485
|
+
create(params: EmbeddingCreateParams, options?: RequestOptions): Promise<Result<CreateEmbeddingResponse>>;
|
|
486
|
+
}
|
|
487
|
+
interface ImageGenerateParams {
|
|
488
|
+
model: string;
|
|
489
|
+
prompt: string;
|
|
490
|
+
/** Forwarded to OpenRouter as `image_config`. Use for aspect ratio, size, etc. */
|
|
491
|
+
imageConfig?: Record<string, unknown>;
|
|
492
|
+
}
|
|
493
|
+
interface ImagesResponse {
|
|
494
|
+
created: number;
|
|
495
|
+
data: GeneratedImage[];
|
|
496
|
+
}
|
|
497
|
+
interface GeneratedImage {
|
|
498
|
+
/** Original `data:image/...;base64,...` URL as returned by OpenRouter. */
|
|
499
|
+
url: string;
|
|
500
|
+
/** Base64 payload extracted from the data URL. */
|
|
501
|
+
b64Json?: string;
|
|
502
|
+
/** MIME type parsed from the data URL prefix. */
|
|
503
|
+
mimeType?: string;
|
|
504
|
+
}
|
|
505
|
+
declare class ImagesNamespace {
|
|
506
|
+
private readonly _getClient;
|
|
507
|
+
private readonly _gate;
|
|
508
|
+
constructor(_getClient: () => Result<OpenAI>, _gate: ModuleGate);
|
|
509
|
+
/**
|
|
510
|
+
* OpenRouter does not implement the OpenAI `/v1/images/generations`
|
|
511
|
+
* endpoint. Image models are reached via `/v1/chat/completions` with
|
|
512
|
+
* `modalities: ['image']`, and the resulting image is returned as a
|
|
513
|
+
* non-standard `message.images[]` array of base64 data URLs. This method
|
|
514
|
+
* encapsulates that quirk and surfaces an OpenAI-shaped response so
|
|
515
|
+
* agent code does not need to know.
|
|
516
|
+
*
|
|
517
|
+
* If the model does not return any images (wrong model, content policy,
|
|
518
|
+
* etc.) this returns an `ai_no_image_generated` error rather than an
|
|
519
|
+
* empty success — surfacing the failure to the caller instead of
|
|
520
|
+
* silently producing zero images.
|
|
521
|
+
*/
|
|
522
|
+
generate(params: ImageGenerateParams, options?: RequestOptions): Promise<Result<ImagesResponse>>;
|
|
523
|
+
}
|
|
524
|
+
interface OpenRouterModel {
|
|
525
|
+
id: string;
|
|
526
|
+
name?: string;
|
|
527
|
+
description?: string;
|
|
528
|
+
context_length?: number;
|
|
529
|
+
pricing?: Record<string, unknown>;
|
|
530
|
+
architecture?: Record<string, unknown>;
|
|
531
|
+
supported_parameters?: string[];
|
|
532
|
+
}
|
|
533
|
+
interface ModelsListResponse {
|
|
534
|
+
data: OpenRouterModel[];
|
|
535
|
+
}
|
|
536
|
+
declare class ModelsNamespace {
|
|
537
|
+
private readonly _getClient;
|
|
538
|
+
private readonly _gate;
|
|
539
|
+
constructor(_getClient: () => Result<OpenAI>, _gate: ModuleGate);
|
|
540
|
+
/**
|
|
541
|
+
* Calls `GET ${baseURL}/models` directly with `fetch` — the upstream
|
|
542
|
+
* `openai.models.list()` parses the response into OpenAI's `Model` type
|
|
543
|
+
* which discards OpenRouter-specific fields (`pricing`, `context_length`,
|
|
544
|
+
* `supported_parameters`, `architecture`). Going through `fetch` keeps
|
|
545
|
+
* the full payload.
|
|
546
|
+
*
|
|
547
|
+
* Reuses the cached `OpenAI` instance (built lazily by `AiModule`) so
|
|
548
|
+
* the resolved `apiKey` and `baseURL` are consistent with the rest of
|
|
549
|
+
* the namespaces — and any `clientOverride` injected for tests applies
|
|
550
|
+
* here too.
|
|
551
|
+
*/
|
|
552
|
+
list(options?: RequestOptions): Promise<Result<ModelsListResponse>>;
|
|
553
|
+
}
|
|
554
|
+
interface RequestOptions {
|
|
555
|
+
signal?: AbortSignal;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Public surface a creator can use through `client.database`. We pin it to the
|
|
560
|
+
* `postgres-js` Drizzle wrapper because that is the only driver `@stackbone/sdk`
|
|
561
|
+
* ships and the only one `STACKBONE_POSTGRES_URL` is contracted to point at.
|
|
562
|
+
*
|
|
563
|
+
* Re-exporting Drizzle's own type instead of inventing a structural alias keeps
|
|
564
|
+
* the surface 1:1 with what `drizzle-orm` documents and what `@stackbone/sdk/db`
|
|
565
|
+
* re-exports — so types flow end to end without translation.
|
|
566
|
+
*/
|
|
567
|
+
type DrizzleClient = PostgresJsDatabase<Record<string, never>> & {
|
|
568
|
+
$client: Sql;
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* `client.database` is a lazy wrapper over a `drizzle()` instance bound to
|
|
573
|
+
* `STACKBONE_POSTGRES_URL`. The underlying postgres-js connection and the
|
|
574
|
+
* Drizzle facade are constructed on the first method call so env vars rotated
|
|
575
|
+
* post-`createClient()` are still honoured.
|
|
576
|
+
*
|
|
577
|
+
* Native Drizzle methods (`select`, `insert`, `update`, `delete`, `transaction`,
|
|
578
|
+
* `execute`) are exposed verbatim — we explicitly avoid wrapping them in a
|
|
579
|
+
* Result envelope here. Drizzle already throws on misuse and returns typed rows
|
|
580
|
+
* on success; mirroring its API keeps the contract identical to what the
|
|
581
|
+
* `@stackbone/sdk/db` re-exports document, so creators write idiomatic Drizzle.
|
|
582
|
+
*
|
|
583
|
+
* Missing `STACKBONE_POSTGRES_URL` raises `SdkError('database_not_configured')`
|
|
584
|
+
* with an actionable hint that points to `stackbone dev`. This is a creator
|
|
585
|
+
* setup bug, not something the agent's code can recover from at runtime.
|
|
586
|
+
*
|
|
587
|
+
* Methods are declared with their full Drizzle generic signatures (rather than
|
|
588
|
+
* `(...args) => Drizzle[k](...args)` arrow properties) so the inferred row
|
|
589
|
+
* types from `pgTable(...)` flow end-to-end into the caller, which is the
|
|
590
|
+
* promise the `@stackbone/sdk/db` re-export makes.
|
|
591
|
+
*
|
|
592
|
+
* The actual `postgres()` pool and the Drizzle handle are owned by the
|
|
593
|
+
* module-internal singleton in `./internal.ts`. `client.database` and any
|
|
594
|
+
* other internal SDK module that imports `getDatabaseHandle` therefore share
|
|
595
|
+
* one pool per agent process — see `internal.spec.ts` for the invariant.
|
|
596
|
+
*/
|
|
597
|
+
declare class DatabaseModule {
|
|
598
|
+
private readonly _resolved;
|
|
599
|
+
private readonly _gate;
|
|
600
|
+
constructor(_resolved: ResolvedConfig,
|
|
601
|
+
/**
|
|
602
|
+
* Test seam — see `ModuleGate`. Defaults to the lazy contract gate.
|
|
603
|
+
* The gate is awaited at the terminal `await` of every Drizzle chain
|
|
604
|
+
* (`select/insert/update/delete/execute/transaction`); when it returns
|
|
605
|
+
* an error, a tagged `GateBlockedError` is thrown so callers see the
|
|
606
|
+
* same `Error & { code, message, meta }` surface as the existing
|
|
607
|
+
* `database_not_configured` setup-bug.
|
|
608
|
+
*/
|
|
609
|
+
gate?: ModuleGate);
|
|
610
|
+
/**
|
|
611
|
+
* Escape hatch — returns Drizzle's relational query builder verbatim. The
|
|
612
|
+
* contract gate does NOT fire here because the surface is a synchronous
|
|
613
|
+
* accessor; the user can still bypass the gate via `client.database.raw()`
|
|
614
|
+
* for the same reason. Audit: `query` and `raw()` are intentionally
|
|
615
|
+
* ungated escape hatches; the standard `select/insert/update/delete/
|
|
616
|
+
* execute/transaction` path is fully gated.
|
|
617
|
+
*/
|
|
618
|
+
get query(): DrizzleClient['query'];
|
|
619
|
+
select: DrizzleClient['select'];
|
|
620
|
+
insert: DrizzleClient['insert'];
|
|
621
|
+
update: DrizzleClient['update'];
|
|
622
|
+
delete: DrizzleClient['delete'];
|
|
623
|
+
execute: DrizzleClient['execute'];
|
|
624
|
+
transaction: DrizzleClient['transaction'];
|
|
625
|
+
/**
|
|
626
|
+
* Escape hatch for callers that want the raw Drizzle handle (e.g. to pass
|
|
627
|
+
* it to a library that expects `PostgresJsDatabase`). Reading this property
|
|
628
|
+
* triggers the same lazy initialisation as any other method but
|
|
629
|
+
* intentionally does NOT consult the contract gate — the surface is sync
|
|
630
|
+
* and the caller is opting out of the SDK's structured surface.
|
|
631
|
+
*/
|
|
632
|
+
raw(): DrizzleClient;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Where a memory lives. Default `'user'`. `'session'` is short-lived and
|
|
637
|
+
* collapsed (or dropped) by `endSession()`; `'agent'` is shared across every
|
|
638
|
+
* user of the agent.
|
|
639
|
+
*/
|
|
640
|
+
type MemoryScope = 'user' | 'session' | 'agent';
|
|
641
|
+
/**
|
|
642
|
+
* Either raw text or an OpenAI-shaped conversation. The future mem0 backend
|
|
643
|
+
* accepts both: strings ingest verbatim, message arrays are summarised into
|
|
644
|
+
* one or more facts.
|
|
645
|
+
*/
|
|
646
|
+
type MemoryContent = string | ChatCompletionMessageParam[];
|
|
647
|
+
interface AddMemoryRequest {
|
|
648
|
+
userId: string;
|
|
649
|
+
/** Conversation/session bucket. Required when `scope: 'session'`. */
|
|
650
|
+
sessionId?: string;
|
|
651
|
+
/** Default `'user'`. */
|
|
652
|
+
scope?: MemoryScope;
|
|
653
|
+
metadata?: Record<string, unknown>;
|
|
654
|
+
}
|
|
655
|
+
interface MemoryItem {
|
|
656
|
+
id: string;
|
|
657
|
+
content: string;
|
|
658
|
+
userId: string;
|
|
659
|
+
sessionId?: string;
|
|
660
|
+
scope: MemoryScope;
|
|
661
|
+
metadata?: Record<string, unknown>;
|
|
662
|
+
/** ISO 8601 UTC timestamp. */
|
|
663
|
+
createdAt: string;
|
|
664
|
+
updatedAt: string;
|
|
665
|
+
}
|
|
666
|
+
interface SearchMemoryOptions {
|
|
667
|
+
userId?: string;
|
|
668
|
+
sessionId?: string;
|
|
669
|
+
/** 1..100. Default 10. */
|
|
670
|
+
limit?: number;
|
|
671
|
+
/** Minimum cosine similarity in [0, 1]. Hits below this are dropped. */
|
|
672
|
+
threshold?: number;
|
|
673
|
+
/** Metadata predicates AND-ed to the semantic match. */
|
|
674
|
+
filters?: Record<string, unknown>;
|
|
675
|
+
/** Restrict the search to a subset of scopes. Default: every scope. */
|
|
676
|
+
includeScopes?: readonly MemoryScope[];
|
|
677
|
+
}
|
|
678
|
+
interface MemoryHit extends MemoryItem {
|
|
679
|
+
/** Cosine similarity in [0, 1]. */
|
|
680
|
+
score: number;
|
|
681
|
+
}
|
|
682
|
+
interface ListMemoryRequest {
|
|
683
|
+
userId: string;
|
|
684
|
+
/** 1..100. Default 50. */
|
|
685
|
+
limit?: number;
|
|
686
|
+
cursor?: string;
|
|
687
|
+
}
|
|
688
|
+
interface ListMemoryResult {
|
|
689
|
+
items: readonly MemoryItem[];
|
|
690
|
+
nextCursor?: string;
|
|
691
|
+
}
|
|
692
|
+
interface UpdateMemoryOptions {
|
|
693
|
+
content?: string;
|
|
694
|
+
/** Shallow-merged onto the existing metadata (mem0 semantics). */
|
|
695
|
+
metadata?: Record<string, unknown>;
|
|
696
|
+
}
|
|
697
|
+
interface DeleteAllMemoryRequest {
|
|
698
|
+
userId: string;
|
|
699
|
+
}
|
|
700
|
+
type MemoryHistoryEvent = 'created' | 'updated' | 'accessed' | 'deleted';
|
|
701
|
+
interface MemoryHistoryEntry {
|
|
702
|
+
id: string;
|
|
703
|
+
memoryId: string;
|
|
704
|
+
event: MemoryHistoryEvent;
|
|
705
|
+
/** ISO 8601 UTC timestamp. */
|
|
706
|
+
at: string;
|
|
707
|
+
/** Identifier of who triggered the event (user id, agent id, etc.). */
|
|
708
|
+
actor?: string;
|
|
709
|
+
/** Content snapshot before the event. Only set for `updated`/`deleted`. */
|
|
710
|
+
before?: string;
|
|
711
|
+
/** Content snapshot after the event. Only set for `created`/`updated`. */
|
|
712
|
+
after?: string;
|
|
713
|
+
metadata?: Record<string, unknown>;
|
|
714
|
+
}
|
|
715
|
+
interface EndSessionOptions {
|
|
716
|
+
/** Persist session-scoped facts to long-term (`'user'`) memory before closing. Default `true`. */
|
|
717
|
+
persist?: boolean;
|
|
718
|
+
}
|
|
719
|
+
interface EndSessionResult {
|
|
720
|
+
sessionId: string;
|
|
721
|
+
/** Number of session memories promoted to long-term storage. `0` when `persist: false`. */
|
|
722
|
+
persisted: number;
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* `client.memory` — long-term memory for the agent. The first iteration is a
|
|
726
|
+
* scaffolding placeholder: every method returns `not_implemented`. The real
|
|
727
|
+
* backend will be mem0 (`mem0ApiKey` / `MEM0_API_KEY`) and the public surface
|
|
728
|
+
* defined here is the contract callers can already type against.
|
|
729
|
+
*/
|
|
730
|
+
declare class MemoryModule {
|
|
731
|
+
private readonly _resolved;
|
|
732
|
+
constructor(_resolved: ResolvedConfig);
|
|
733
|
+
add(_content: MemoryContent, _request: AddMemoryRequest): Promise<Result<MemoryItem>>;
|
|
734
|
+
search(_query: string, _options?: SearchMemoryOptions): Promise<Result<readonly MemoryHit[]>>;
|
|
735
|
+
delete(_memoryId: string): Promise<Result<{
|
|
736
|
+
id: string;
|
|
737
|
+
}>>;
|
|
738
|
+
deleteAll(_request: DeleteAllMemoryRequest): Promise<Result<{
|
|
739
|
+
deleted: number;
|
|
740
|
+
}>>;
|
|
741
|
+
get(_memoryId: string): Promise<Result<MemoryItem>>;
|
|
742
|
+
list(_request: ListMemoryRequest): Promise<Result<ListMemoryResult>>;
|
|
743
|
+
update(_memoryId: string, _options: UpdateMemoryOptions): Promise<Result<MemoryItem>>;
|
|
744
|
+
history(_memoryId: string): Promise<Result<readonly MemoryHistoryEntry[]>>;
|
|
745
|
+
endSession(_sessionId: string, _options?: EndSessionOptions): Promise<Result<EndSessionResult>>;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
declare const RUN_STEP_TYPES: readonly ["agent", "llm_call", "db_query", "http_fetch", "queue_publish", "hitl_pause", "tool_call", "rag_query", "storage_op"];
|
|
749
|
+
type RunStepType = (typeof RUN_STEP_TYPES)[number];
|
|
750
|
+
declare const STEP_TYPE_ATTRIBUTE = "stackbone.step.type";
|
|
751
|
+
declare const RUN_ID_ATTRIBUTE = "stackbone.run.id";
|
|
752
|
+
/**
|
|
753
|
+
* Minimal duck-typed view of an OpenTelemetry `ReadableSpan`. We mirror the
|
|
754
|
+
* shape the OTel SDK exposes on `@opentelemetry/sdk-trace-base` rather than
|
|
755
|
+
* importing the package so `@stackbone/sdk` doesn't pull the OTel runtime into
|
|
756
|
+
* every agent that doesn't enable Studio. Agents wire the processor with
|
|
757
|
+
* `provider.addSpanProcessor(new RunStepsSpanProcessor(...))` and the
|
|
758
|
+
* structural match satisfies TypeScript.
|
|
759
|
+
*/
|
|
760
|
+
interface SpanContextLike {
|
|
761
|
+
spanId: string;
|
|
762
|
+
traceId: string;
|
|
763
|
+
}
|
|
764
|
+
interface ReadableSpanLike {
|
|
765
|
+
spanContext(): SpanContextLike;
|
|
766
|
+
parentSpanContext?: SpanContextLike | undefined;
|
|
767
|
+
parentSpanId?: string | undefined;
|
|
768
|
+
name: string;
|
|
769
|
+
attributes: Record<string, unknown>;
|
|
770
|
+
status?: {
|
|
771
|
+
code: number;
|
|
772
|
+
message?: string;
|
|
773
|
+
} | undefined;
|
|
774
|
+
startTime?: [number, number] | undefined;
|
|
775
|
+
endTime?: [number, number] | undefined;
|
|
776
|
+
duration?: [number, number] | undefined;
|
|
777
|
+
}
|
|
778
|
+
interface PostgresLike {
|
|
779
|
+
unsafe(query: string, params?: unknown[]): Promise<unknown>;
|
|
780
|
+
end?(): Promise<void>;
|
|
781
|
+
}
|
|
782
|
+
interface RunStepsSpanProcessorOptions {
|
|
783
|
+
/**
|
|
784
|
+
* Postgres connection string of the install (local emulator at :5433 in
|
|
785
|
+
* dev, Neon TCP/HTTP URL in cloud). Falls back to `DATABASE_URL`.
|
|
786
|
+
*/
|
|
787
|
+
connectionString?: string | undefined;
|
|
788
|
+
/** Flush trigger by buffer size. Defaults to 50. */
|
|
789
|
+
flushBatchSize?: number | undefined;
|
|
790
|
+
/** Flush trigger by elapsed time (ms). Defaults to 500. */
|
|
791
|
+
flushIntervalMs?: number | undefined;
|
|
792
|
+
/** Override how a span maps to a step type. */
|
|
793
|
+
resolveStepType?: ((span: ReadableSpanLike) => RunStepType) | undefined;
|
|
794
|
+
/** Test seam — inject a postgres-js-compatible client. */
|
|
795
|
+
sql?: PostgresLike | undefined;
|
|
796
|
+
/** Test seam — deterministic UUID generator. */
|
|
797
|
+
newId?: (() => string) | undefined;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Materialises every OTel span produced by the agent into a row of
|
|
801
|
+
* `stackbone_platform.run_steps`. Designed to coexist with the OTLP exporter:
|
|
802
|
+
* cloud builds register both processors so Postgres feeds Studio (paridad
|
|
803
|
+
* con local) and Tempo feeds Platform Ops with retention/aggregation. If a
|
|
804
|
+
* write fails the processor logs to stderr and keeps accepting spans —
|
|
805
|
+
* observability is never load-bearing for agent execution.
|
|
806
|
+
*
|
|
807
|
+
* Spec: docs/arquitectura/specs/stackbone-agent-protocol-v1.md §6.3
|
|
808
|
+
* ADR: docs/arquitectura/decisiones/2026-05-03-stackbone-studio-datapath-y-scope-mvp.md §D9
|
|
809
|
+
*/
|
|
810
|
+
declare class RunStepsSpanProcessor {
|
|
811
|
+
private readonly buffer;
|
|
812
|
+
private readonly stepIdBySpanId;
|
|
813
|
+
private readonly batchSize;
|
|
814
|
+
private readonly intervalMs;
|
|
815
|
+
private readonly resolveStepType;
|
|
816
|
+
private readonly newId;
|
|
817
|
+
private readonly connectionString;
|
|
818
|
+
private readonly ownsSql;
|
|
819
|
+
private sql;
|
|
820
|
+
private timer;
|
|
821
|
+
private inFlight;
|
|
822
|
+
constructor(options?: RunStepsSpanProcessorOptions);
|
|
823
|
+
onStart(span: ReadableSpanLike): void;
|
|
824
|
+
onEnd(span: ReadableSpanLike): void;
|
|
825
|
+
forceFlush(): Promise<void>;
|
|
826
|
+
shutdown(): Promise<void>;
|
|
827
|
+
private buildRow;
|
|
828
|
+
private armTimer;
|
|
829
|
+
private disarmTimer;
|
|
830
|
+
private flush;
|
|
831
|
+
private ensureSql;
|
|
832
|
+
private writeBatch;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
interface AggregateRunCostOptions {
|
|
836
|
+
sql: PostgresLike;
|
|
837
|
+
}
|
|
838
|
+
interface AggregateRunCostResult {
|
|
839
|
+
costEstimatedUsd: number;
|
|
840
|
+
}
|
|
841
|
+
declare function aggregateRunCost(runId: string, options: AggregateRunCostOptions): Promise<AggregateRunCostResult>;
|
|
842
|
+
|
|
843
|
+
declare const LOG_LEVELS: {
|
|
844
|
+
readonly trace: 10;
|
|
845
|
+
readonly debug: 20;
|
|
846
|
+
readonly info: 30;
|
|
847
|
+
readonly warn: 40;
|
|
848
|
+
readonly error: 50;
|
|
849
|
+
readonly fatal: 60;
|
|
850
|
+
};
|
|
851
|
+
type LogLevelName = keyof typeof LOG_LEVELS;
|
|
852
|
+
type LogLevelNumber = (typeof LOG_LEVELS)[LogLevelName];
|
|
853
|
+
interface LogRecord {
|
|
854
|
+
/** Pino-style numeric level. */
|
|
855
|
+
level: LogLevelNumber;
|
|
856
|
+
/** Epoch milliseconds. Pino uses `time` as a number. */
|
|
857
|
+
time: number;
|
|
858
|
+
msg: string;
|
|
859
|
+
run_id: string;
|
|
860
|
+
trace_id?: string;
|
|
861
|
+
installation_id?: string;
|
|
862
|
+
agent_id?: string;
|
|
863
|
+
[key: string]: unknown;
|
|
864
|
+
}
|
|
865
|
+
interface PlatformLoggerOptions {
|
|
866
|
+
runId: string;
|
|
867
|
+
installationId?: string | undefined;
|
|
868
|
+
agentId?: string | undefined;
|
|
869
|
+
/**
|
|
870
|
+
* When set (cloud), logs are batched and POSTed to `<endpoint>/v1/logs` as
|
|
871
|
+
* OTLP/HTTP/JSON. When unset (local), logs are appended to
|
|
872
|
+
* `<runsDir>/<runId>.jsonl`. Falls back to `OTEL_EXPORTER_OTLP_ENDPOINT`.
|
|
873
|
+
*/
|
|
874
|
+
otelEndpoint?: string | undefined;
|
|
875
|
+
/** Local-only: directory where JSONL files live. Defaults to `~/.stackbone/dev/runs`. */
|
|
876
|
+
runsDir?: string | undefined;
|
|
877
|
+
/** Cloud-only: extra OTel resource attributes to send with every batch. */
|
|
878
|
+
resourceAttributes?: Record<string, string> | undefined;
|
|
879
|
+
/** Cloud-only: HTTP timeout per OTLP POST in ms. Defaults to 5_000. */
|
|
880
|
+
httpTimeoutMs?: number | undefined;
|
|
881
|
+
/** Flush trigger by buffer size. Defaults to 50. */
|
|
882
|
+
flushBatchSize?: number | undefined;
|
|
883
|
+
/** Flush trigger by elapsed time (ms). Defaults to 1_000. */
|
|
884
|
+
flushIntervalMs?: number | undefined;
|
|
885
|
+
/** Test seam — fetch implementation. Defaults to global `fetch`. */
|
|
886
|
+
fetchImpl?: typeof fetch | undefined;
|
|
887
|
+
/** Test seam — `fs.appendFile`-shaped sink the local destination uses. */
|
|
888
|
+
appendFileImpl?: ((path: string, data: string) => Promise<void>) | undefined;
|
|
889
|
+
/** Test seam — `fs.mkdir`-shaped helper the local destination uses. */
|
|
890
|
+
mkdirImpl?: ((path: string) => Promise<void>) | undefined;
|
|
891
|
+
/** Test seam — clock for `time` field. Defaults to `Date.now`. */
|
|
892
|
+
now?: (() => number) | undefined;
|
|
893
|
+
/** Override mode resolution (skips the env detection). */
|
|
894
|
+
mode?: PlatformLoggerMode | undefined;
|
|
895
|
+
}
|
|
896
|
+
type PlatformLoggerMode = 'local' | 'cloud';
|
|
897
|
+
interface PinoLike {
|
|
898
|
+
trace(msgOrObj: unknown, msg?: string): void;
|
|
899
|
+
debug(msgOrObj: unknown, msg?: string): void;
|
|
900
|
+
info(msgOrObj: unknown, msg?: string): void;
|
|
901
|
+
warn(msgOrObj: unknown, msg?: string): void;
|
|
902
|
+
error(msgOrObj: unknown, msg?: string): void;
|
|
903
|
+
fatal(msgOrObj: unknown, msg?: string): void;
|
|
904
|
+
}
|
|
905
|
+
interface PlatformLogger extends PinoLike {
|
|
906
|
+
readonly mode: PlatformLoggerMode;
|
|
907
|
+
/** Bind extra fields and return a child logger sharing the same destination. */
|
|
908
|
+
child(bindings: Record<string, unknown>): PlatformLogger;
|
|
909
|
+
/** Force-flush pending writes (close file handle or POST OTLP batch). */
|
|
910
|
+
flush(): Promise<void>;
|
|
911
|
+
/** Stop accepting writes and release resources. */
|
|
912
|
+
close(): Promise<void>;
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* Creates a Pino-aligned logger that writes JSONL to disk in local mode and
|
|
916
|
+
* batches OTLP/HTTP/JSON log records to an OTel collector in cloud mode. Mode
|
|
917
|
+
* is resolved from `OTEL_EXPORTER_OTLP_ENDPOINT` or the explicit override.
|
|
918
|
+
*/
|
|
919
|
+
declare function createPlatformLogger(options: PlatformLoggerOptions): PlatformLogger;
|
|
920
|
+
declare function defaultRunsDir(): string;
|
|
921
|
+
|
|
922
|
+
declare class ObservabilityModule {
|
|
923
|
+
private readonly _resolved;
|
|
924
|
+
private _processor?;
|
|
925
|
+
private readonly _loggers;
|
|
926
|
+
private _sql;
|
|
927
|
+
private _sqlResolved;
|
|
928
|
+
constructor(_resolved: ResolvedConfig);
|
|
929
|
+
/**
|
|
930
|
+
* Singleton SpanProcessor that the agent registers in its OTel
|
|
931
|
+
* TracerProvider. Coexists with the OTLP exporter — cloud builds wire
|
|
932
|
+
* both so Postgres feeds Studio (paridad con local) and Tempo feeds
|
|
933
|
+
* Platform Ops.
|
|
934
|
+
*/
|
|
935
|
+
spanProcessor(options?: RunStepsSpanProcessorOptions): RunStepsSpanProcessor;
|
|
936
|
+
flush(): Promise<Result<void>>;
|
|
937
|
+
/**
|
|
938
|
+
* Per-run structured logger. In local mode (no `OTEL_EXPORTER_OTLP_ENDPOINT`)
|
|
939
|
+
* appends JSONL to `~/.stackbone/dev/runs/<runId>.jsonl`; in cloud mode batches
|
|
940
|
+
* OTLP/HTTP/JSON log records to the collector. Cached by `runId` so the
|
|
941
|
+
* file handle / buffered timer stays stable across repeated calls inside
|
|
942
|
+
* the same run.
|
|
943
|
+
*/
|
|
944
|
+
logger(options: {
|
|
945
|
+
runId: string;
|
|
946
|
+
} & Partial<PlatformLoggerOptions>): PlatformLogger;
|
|
947
|
+
/** Closes the per-run logger (flushes the JSONL file or the OTLP buffer). */
|
|
948
|
+
closeLogger(runId: string): Promise<void>;
|
|
949
|
+
/**
|
|
950
|
+
* Hook the agent calls when a run finishes. Sums `cost_usd` from every
|
|
951
|
+
* `llm_call` span of the run and writes the total to
|
|
952
|
+
* `stackbone_platform.runs.cost_estimated_usd`. Errors are folded into the
|
|
953
|
+
* Result envelope so the agent's run cleanup never aborts on a flaky
|
|
954
|
+
* Postgres call — the cost is decorative metadata, not load-bearing.
|
|
955
|
+
*/
|
|
956
|
+
closeRun(runId: string): Promise<Result<AggregateRunCostResult>>;
|
|
957
|
+
private resolveSql;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
interface PublishRequest {
|
|
961
|
+
url: string;
|
|
962
|
+
body: unknown;
|
|
963
|
+
retries?: number;
|
|
964
|
+
delay?: number;
|
|
965
|
+
deduplicationId?: string;
|
|
966
|
+
headers?: Record<string, string>;
|
|
967
|
+
}
|
|
968
|
+
declare class QueuesModule {
|
|
969
|
+
private readonly _gate;
|
|
970
|
+
constructor(resolved: ResolvedConfig,
|
|
971
|
+
/** Test seam — see `ModuleGate`. Defaults to the lazy contract gate. */
|
|
972
|
+
gate?: ModuleGate);
|
|
973
|
+
publish(_request: PublishRequest): Promise<Result<{
|
|
974
|
+
messageId: string;
|
|
975
|
+
}>>;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
type ChunkStrategy = 'recursive' | 'sentence';
|
|
979
|
+
interface ChunkOptions {
|
|
980
|
+
/** Splitter algorithm. Default `recursive`. */
|
|
981
|
+
strategy?: ChunkStrategy;
|
|
982
|
+
/** Target characters per chunk. Default 512. */
|
|
983
|
+
size?: number;
|
|
984
|
+
/** Characters of overlap between consecutive chunks. Default 64. */
|
|
985
|
+
overlap?: number;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
type RagIngestProgress = {
|
|
989
|
+
type: 'started';
|
|
990
|
+
jobId: string;
|
|
991
|
+
totalChunks: number;
|
|
992
|
+
} | {
|
|
993
|
+
type: 'progress';
|
|
994
|
+
jobId: string;
|
|
995
|
+
processedChunks: number;
|
|
996
|
+
totalChunks: number;
|
|
997
|
+
currentDocument?: {
|
|
998
|
+
source: string;
|
|
999
|
+
ordinal: number;
|
|
1000
|
+
};
|
|
1001
|
+
} | {
|
|
1002
|
+
type: 'completed';
|
|
1003
|
+
jobId: string;
|
|
1004
|
+
totalChunks: number;
|
|
1005
|
+
} | {
|
|
1006
|
+
type: 'failed';
|
|
1007
|
+
jobId: string;
|
|
1008
|
+
error: string;
|
|
1009
|
+
};
|
|
1010
|
+
|
|
1011
|
+
interface ParseOptions {
|
|
1012
|
+
/** MIME type override. If omitted, the parser sniffs the input (Blob.type or PDF magic bytes). */
|
|
1013
|
+
mime?: string;
|
|
1014
|
+
}
|
|
1015
|
+
type ParseInput = Blob | string | Uint8Array | ArrayBuffer;
|
|
1016
|
+
|
|
1017
|
+
interface IngestChunk {
|
|
1018
|
+
content: string;
|
|
1019
|
+
embedding: number[];
|
|
1020
|
+
}
|
|
1021
|
+
interface IngestRequestBase {
|
|
1022
|
+
/** Document identifier — re-ingesting with the same `id` replaces all its chunks atomically. */
|
|
1023
|
+
id: string;
|
|
1024
|
+
metadata?: Record<string, unknown>;
|
|
1025
|
+
/** Logical namespace for separation. Default `'default'`. */
|
|
1026
|
+
namespace?: string;
|
|
1027
|
+
/**
|
|
1028
|
+
* Canonical collection name used by the `stackbone_rag_jobs` writer (F07)
|
|
1029
|
+
* to bind the row to a `stackbone_rag_collections` parent. Optional for
|
|
1030
|
+
* back-compat with pre-F07 callers — when absent, no job row is written
|
|
1031
|
+
* and progress is delivered only via `onProgress` (if any).
|
|
1032
|
+
*/
|
|
1033
|
+
collection?: string;
|
|
1034
|
+
/**
|
|
1035
|
+
* Optional sink for streaming progress events. Fired in addition to (and
|
|
1036
|
+
* before) the matching `IngestJobWriter` call so synchronous `ingest`
|
|
1037
|
+
* consumers can observe progress without paying the SQL writer cost.
|
|
1038
|
+
*/
|
|
1039
|
+
onProgress?: (event: RagIngestProgress) => void | Promise<void>;
|
|
1040
|
+
}
|
|
1041
|
+
interface IngestRequestPrecomputed extends IngestRequestBase {
|
|
1042
|
+
chunks: IngestChunk[];
|
|
1043
|
+
}
|
|
1044
|
+
interface IngestRequestAutoEmbed extends IngestRequestBase {
|
|
1045
|
+
chunks: string[];
|
|
1046
|
+
/** Embedding model id. When set, the pipeline calls the configured Embedder. */
|
|
1047
|
+
model: string;
|
|
1048
|
+
/**
|
|
1049
|
+
* Items per embeddings request. Consumed by the facade when it builds the
|
|
1050
|
+
* `Embedder`; ignored by the pipeline itself (the embedder is fully
|
|
1051
|
+
* configured at construction time).
|
|
1052
|
+
*/
|
|
1053
|
+
batchSize?: number;
|
|
1054
|
+
}
|
|
1055
|
+
type IngestRequest = IngestRequestPrecomputed | IngestRequestAutoEmbed;
|
|
1056
|
+
interface IngestResponse {
|
|
1057
|
+
id: string;
|
|
1058
|
+
chunks: number;
|
|
1059
|
+
}
|
|
1060
|
+
interface DeleteOptions {
|
|
1061
|
+
namespace?: string;
|
|
1062
|
+
}
|
|
1063
|
+
interface DeleteResponse {
|
|
1064
|
+
deleted: number;
|
|
1065
|
+
}
|
|
1066
|
+
interface RetrieveRequestBase {
|
|
1067
|
+
topK?: number;
|
|
1068
|
+
filter?: Record<string, unknown>;
|
|
1069
|
+
namespace?: string;
|
|
1070
|
+
includeContent?: boolean;
|
|
1071
|
+
includeMetadata?: boolean;
|
|
1072
|
+
}
|
|
1073
|
+
interface RetrieveRequestPrecomputed extends RetrieveRequestBase {
|
|
1074
|
+
embedding: number[];
|
|
1075
|
+
}
|
|
1076
|
+
interface RetrieveRequestAutoEmbed extends RetrieveRequestBase {
|
|
1077
|
+
text: string;
|
|
1078
|
+
/** Must match the model used at ingest time. */
|
|
1079
|
+
model: string;
|
|
1080
|
+
}
|
|
1081
|
+
type RetrieveRequest = RetrieveRequestPrecomputed | RetrieveRequestAutoEmbed;
|
|
1082
|
+
interface RetrieveHit {
|
|
1083
|
+
id: string;
|
|
1084
|
+
chunkIdx: number;
|
|
1085
|
+
content?: string;
|
|
1086
|
+
metadata?: Record<string, unknown>;
|
|
1087
|
+
score: number;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
/**
|
|
1091
|
+
* Handle returned by `client.rag.ingestAsync`. The job id is allocated
|
|
1092
|
+
* synchronously against `stackbone_rag_jobs` so the caller can track / cancel
|
|
1093
|
+
* the work via the `/api/rag/jobs/:jobId/*` surface; `events` is a streaming
|
|
1094
|
+
* channel of progress events (ADR §D9 shape); `result` settles when the
|
|
1095
|
+
* pipeline finishes (or fails / is cancelled).
|
|
1096
|
+
*/
|
|
1097
|
+
interface IngestAsyncHandle {
|
|
1098
|
+
jobId: string;
|
|
1099
|
+
events: AsyncIterable<RagIngestProgress>;
|
|
1100
|
+
result: Promise<Result<IngestResponse>>;
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* `client.rag` — `pgvector`-backed retrieval. Two shapes per write/read:
|
|
1104
|
+
* pass `model` to let the SDK embed for you; pass embeddings precomputed for
|
|
1105
|
+
* provider/dimension/batching control.
|
|
1106
|
+
*
|
|
1107
|
+
* Implementation note: `RagModule` is a thin facade over `RagPipeline`. The
|
|
1108
|
+
* pipeline owns parse → chunk → embed → persist; the facade resolves the
|
|
1109
|
+
* shared `client.database` pool, builds an `Embedder` on demand, and maps
|
|
1110
|
+
* configuration errors. See ADR `2026-05-10-rag-consolidation-on-client-database`.
|
|
1111
|
+
*
|
|
1112
|
+
* Connection ownership: this module never opens its own postgres pool. It
|
|
1113
|
+
* pulls the underlying `postgres-js` `Sql` from the shared
|
|
1114
|
+
* `getDatabaseHandle()` exposed by `client.database`, so an agent that
|
|
1115
|
+
* touches both surfaces still opens exactly one connection pool against
|
|
1116
|
+
* `STACKBONE_POSTGRES_URL`.
|
|
1117
|
+
*
|
|
1118
|
+
* Schema readiness: starting with feature 30, the canonical schema is
|
|
1119
|
+
* installed by the CLI (`stackbone db migrate add-rag` + `migrate up`). When
|
|
1120
|
+
* an operation hits `42P01 relation does not exist`, the pipeline returns
|
|
1121
|
+
* `SdkError('rag_schema_missing')` with an actionable hint.
|
|
1122
|
+
*/
|
|
1123
|
+
declare class RagModule {
|
|
1124
|
+
private readonly _resolved;
|
|
1125
|
+
private readonly _getAi;
|
|
1126
|
+
private readonly _gate;
|
|
1127
|
+
constructor(_resolved: ResolvedConfig, _getAi: () => AiModule,
|
|
1128
|
+
/** Test seam — see `ModuleGate`. Defaults to the lazy contract gate. */
|
|
1129
|
+
gate?: ModuleGate);
|
|
1130
|
+
ingest(request: IngestRequest): Promise<Result<IngestResponse>>;
|
|
1131
|
+
/**
|
|
1132
|
+
* Asynchronous ingest. Allocates a `stackbone_rag_jobs` row, returns the
|
|
1133
|
+
* job id immediately, and exposes both an `AsyncIterable` of streaming
|
|
1134
|
+
* progress events and the final `Result` so callers can `await` either
|
|
1135
|
+
* surface — typical webhook handlers consume `events` and ignore `result`,
|
|
1136
|
+
* tests `await result` directly. Cancellation is observed by flipping the
|
|
1137
|
+
* row's status (e.g. via `POST /api/rag/jobs/:jobId/cancel`); the worker
|
|
1138
|
+
* polls between chunk batches and bails out with `rag_ingest_cancelled`.
|
|
1139
|
+
*
|
|
1140
|
+
* Connection ownership: the `IngestJobWriter` is bound to the same SQL
|
|
1141
|
+
* pulled off the shared `client.database` handle, so a single agent that
|
|
1142
|
+
* issues `ingestAsync` and `client.database.select` in flight still opens
|
|
1143
|
+
* exactly one pool against `STACKBONE_POSTGRES_URL`.
|
|
1144
|
+
*/
|
|
1145
|
+
ingestAsync(request: IngestRequest): Promise<Result<IngestAsyncHandle>>;
|
|
1146
|
+
/** Test-only seam — assigned by `ingest-async.spec.ts`. */
|
|
1147
|
+
private _testJobWriter?;
|
|
1148
|
+
/** Test-only seam — assigned by `ingest-async.spec.ts`. */
|
|
1149
|
+
private _testSqlOverride?;
|
|
1150
|
+
delete(ids: string | string[], options?: DeleteOptions): Promise<Result<DeleteResponse>>;
|
|
1151
|
+
deleteWhere(filter: Record<string, unknown>, options?: DeleteOptions): Promise<Result<DeleteResponse>>;
|
|
1152
|
+
retrieve(request: RetrieveRequest): Promise<Result<RetrieveHit[]>>;
|
|
1153
|
+
/**
|
|
1154
|
+
* Drops the legacy ad-hoc RAG schema. Kept for backwards compatibility with
|
|
1155
|
+
* pre-feature-30 agents whose tables were provisioned by `ensureSchema` on
|
|
1156
|
+
* first call. The canonical RAG schema (feature 30) is owned by the CLI and
|
|
1157
|
+
* removed via `stackbone db migrate` flows, not by this method.
|
|
1158
|
+
*/
|
|
1159
|
+
reset(): Promise<Result<void>>;
|
|
1160
|
+
/**
|
|
1161
|
+
* Pure helper — exposed verbatim from the chunker. No DB, no AI, no
|
|
1162
|
+
* datapath traffic, so it is intentionally NOT gated.
|
|
1163
|
+
*/
|
|
1164
|
+
chunk(text: string, options?: ChunkOptions): string[];
|
|
1165
|
+
/**
|
|
1166
|
+
* Pure helper — exposed verbatim from the parser. No DB, no AI, no
|
|
1167
|
+
* datapath traffic, so it is intentionally NOT gated.
|
|
1168
|
+
*/
|
|
1169
|
+
parse(input: ParseInput, options?: ParseOptions): Promise<string>;
|
|
1170
|
+
/**
|
|
1171
|
+
* Resolves the postgres-js `Sql` to use for this operation. Pulls `$client`
|
|
1172
|
+
* off the shared Drizzle handle (single pool per agent process). Slice F03's
|
|
1173
|
+
* NOTE about cross-module transaction propagation lives here: this is the
|
|
1174
|
+
* seam where a future `database.transaction` integration plugs a tx-bound
|
|
1175
|
+
* `Sql` into the pipeline instead of the pool-bound one.
|
|
1176
|
+
*
|
|
1177
|
+
* Configuration errors (`STACKBONE_POSTGRES_URL` unset) flow up as a
|
|
1178
|
+
* `Result.err` with the same `database_not_configured` shape `client.database`
|
|
1179
|
+
* raises, instead of throwing through the public surface.
|
|
1180
|
+
*/
|
|
1181
|
+
private sql;
|
|
1182
|
+
private withPipeline;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
interface StorageObject {
|
|
1186
|
+
key: string;
|
|
1187
|
+
size: number;
|
|
1188
|
+
lastModified?: Date;
|
|
1189
|
+
etag?: string;
|
|
1190
|
+
}
|
|
1191
|
+
interface UploadOptions {
|
|
1192
|
+
contentType?: string;
|
|
1193
|
+
metadata?: Record<string, string>;
|
|
1194
|
+
}
|
|
1195
|
+
interface ListOptions {
|
|
1196
|
+
prefix?: string;
|
|
1197
|
+
/** Maximum number of objects to return per page. Must be > 0. */
|
|
1198
|
+
limit?: number;
|
|
1199
|
+
cursor?: string;
|
|
1200
|
+
}
|
|
1201
|
+
interface SignedUrlOptions {
|
|
1202
|
+
/** Seconds until the URL expires. Defaults to 3600 (1h). */
|
|
1203
|
+
expiresIn?: number;
|
|
1204
|
+
/** Only honoured by `getSignedUploadUrl` — pinned into the signature so the uploader must send a matching `Content-Type`. */
|
|
1205
|
+
contentType?: string;
|
|
1206
|
+
}
|
|
1207
|
+
interface SignedUrl {
|
|
1208
|
+
url: string;
|
|
1209
|
+
expiresAt: Date;
|
|
1210
|
+
}
|
|
1211
|
+
type StorageBody = Blob | Uint8Array | string;
|
|
1212
|
+
interface S3Settings {
|
|
1213
|
+
client: S3Client;
|
|
1214
|
+
endpoint: string;
|
|
1215
|
+
bucket: string;
|
|
1216
|
+
agentId: string;
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Public surface behind `client.storage`. Wraps `@aws-sdk/client-s3` against
|
|
1220
|
+
* R2 (prod) or MinIO (dev). Exposes a bucket-scoped API via `from(bucket)`.
|
|
1221
|
+
*
|
|
1222
|
+
* Multi-tenancy: every key is prefixed with `agentId/bucket/` before hitting
|
|
1223
|
+
* S3. Credentials are scoped to the agent's physical bucket (env `S3_BUCKET`),
|
|
1224
|
+
* and the `bucket` argument is a logical namespace the agent uses to organise
|
|
1225
|
+
* its own objects. The full prefixed key is an internal detail — public
|
|
1226
|
+
* methods accept and return the user-facing key (without prefix). Metadata
|
|
1227
|
+
* tracking in `_storage_objects` (Neon) is out-of-scope for this iteration.
|
|
1228
|
+
*
|
|
1229
|
+
* Memory note: `download()` materialises the whole object as a `Blob` in
|
|
1230
|
+
* memory. For agents that need to stream large objects, prefer
|
|
1231
|
+
* `getSignedDownloadUrl()` and `fetch()` the URL directly to consume the
|
|
1232
|
+
* stream incrementally.
|
|
1233
|
+
*/
|
|
1234
|
+
declare class StorageModule {
|
|
1235
|
+
private readonly _resolved;
|
|
1236
|
+
private _s3;
|
|
1237
|
+
private readonly _gate;
|
|
1238
|
+
constructor(_resolved: ResolvedConfig,
|
|
1239
|
+
/** Test seam — see `ModuleGate`. Defaults to the lazy contract gate. */
|
|
1240
|
+
gate?: ModuleGate);
|
|
1241
|
+
from(bucket: string): StorageBucket;
|
|
1242
|
+
private settings;
|
|
1243
|
+
}
|
|
1244
|
+
declare class StorageBucket {
|
|
1245
|
+
private readonly bucketName;
|
|
1246
|
+
private readonly resolveSettings;
|
|
1247
|
+
private readonly gate;
|
|
1248
|
+
constructor(bucketName: string, resolveSettings: () => Result<S3Settings>, gate: ModuleGate);
|
|
1249
|
+
upload(key: string, body: StorageBody, options?: UploadOptions): Promise<Result<{
|
|
1250
|
+
key: string;
|
|
1251
|
+
etag?: string;
|
|
1252
|
+
}>>;
|
|
1253
|
+
download(key: string): Promise<Result<Blob>>;
|
|
1254
|
+
list(options?: ListOptions): Promise<Result<{
|
|
1255
|
+
objects: readonly StorageObject[];
|
|
1256
|
+
nextCursor?: string;
|
|
1257
|
+
}>>;
|
|
1258
|
+
remove(key: string): Promise<Result<{
|
|
1259
|
+
key: string;
|
|
1260
|
+
}>>;
|
|
1261
|
+
/**
|
|
1262
|
+
* Returns the canonical S3-style URL for an object. Pure URL-builder — no
|
|
1263
|
+
* S3 round-trip — so this method intentionally bypasses the contract gate.
|
|
1264
|
+
* Whether the URL is publicly fetchable depends on the bucket policy; for
|
|
1265
|
+
* private buckets, use `getSignedDownloadUrl` instead.
|
|
1266
|
+
*/
|
|
1267
|
+
getPublicUrl(key: string): Result<string>;
|
|
1268
|
+
getSignedUploadUrl(key: string, options?: SignedUrlOptions): Promise<Result<SignedUrl>>;
|
|
1269
|
+
getSignedDownloadUrl(key: string, options?: SignedUrlOptions): Promise<Result<SignedUrl>>;
|
|
1270
|
+
/**
|
|
1271
|
+
* Resolves S3 settings, validates the user key, and prefixes it with
|
|
1272
|
+
* `${agentId}/${bucketName}/`. Rejects path-traversal segments (`..`) so a
|
|
1273
|
+
* caller-controlled key cannot escape the agent's namespace.
|
|
1274
|
+
*/
|
|
1275
|
+
private resolve;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
/**
|
|
1279
|
+
* Each accessor builds its module on first access and caches it — env vars
|
|
1280
|
+
* and partner SDK init costs are paid only when the agent actually touches
|
|
1281
|
+
* that surface.
|
|
1282
|
+
*/
|
|
1283
|
+
declare class StackboneClient {
|
|
1284
|
+
private readonly resolved;
|
|
1285
|
+
private _database?;
|
|
1286
|
+
private _storage?;
|
|
1287
|
+
private _ai?;
|
|
1288
|
+
private _queues?;
|
|
1289
|
+
private _rag?;
|
|
1290
|
+
private _memory?;
|
|
1291
|
+
private _observability?;
|
|
1292
|
+
private _approval?;
|
|
1293
|
+
private _secrets?;
|
|
1294
|
+
private _connections?;
|
|
1295
|
+
private _config?;
|
|
1296
|
+
private _events?;
|
|
1297
|
+
private _prompts?;
|
|
1298
|
+
private _httpClient?;
|
|
1299
|
+
constructor(resolved: ResolvedConfig);
|
|
1300
|
+
private http;
|
|
1301
|
+
get database(): DatabaseModule;
|
|
1302
|
+
get storage(): StorageModule;
|
|
1303
|
+
get ai(): AiModule;
|
|
1304
|
+
get queues(): QueuesModule;
|
|
1305
|
+
get rag(): RagModule;
|
|
1306
|
+
get memory(): MemoryModule;
|
|
1307
|
+
get observability(): ObservabilityModule;
|
|
1308
|
+
get approval(): ApprovalFacade;
|
|
1309
|
+
get secrets(): SecretsFacade;
|
|
1310
|
+
get connections(): ConnectionsFacade;
|
|
1311
|
+
get config(): ConfigFacade;
|
|
1312
|
+
get events(): EventsFacade;
|
|
1313
|
+
get prompts(): PromptsFacade;
|
|
1314
|
+
/**
|
|
1315
|
+
* Read-only view of the most recently resolved Stackbone Agent Protocol
|
|
1316
|
+
* contract for this client's `stackboneApiUrl`. Returns `null` until a
|
|
1317
|
+
* handshake has resolved successfully (the handshake fires lazily on the
|
|
1318
|
+
* first gated module call — slices #4/#5). Synchronous, never throws,
|
|
1319
|
+
* performs no fetches.
|
|
1320
|
+
*/
|
|
1321
|
+
get contract(): ContractResponse | null;
|
|
1322
|
+
}
|
|
1323
|
+
declare function createClient(config?: ClientConfig): StackboneClient;
|
|
1324
|
+
|
|
1325
|
+
export { type AddMemoryRequest, type AggregateRunCostOptions, type AggregateRunCostResult, type ApprovalListOptions, type ApprovalListResult, type ApprovalRecord, type ApprovalRequest, type ApprovalRequestOptions, type ApprovalStatus, type ApprovalTool, type ApprovalToolSpec, type ApprovalTopic, type ApproverInfo, type ChunkOptions, type ChunkStrategy, type ClientConfig, type CreatePromptRequest, type Decision, type DecisionStatus, type DeleteAllMemoryRequest, type DeleteOptions, type DeletePromptOptions, type DeletePromptResult, type DeleteResponse, type EndSessionOptions, type EndSessionResult, type GeneratedImage, type GetPromptOptions, type ImageGenerateParams, type ImagesResponse, type IngestAsyncHandle, type IngestChunk, type IngestRequest, type IngestRequestAutoEmbed, type IngestRequestPrecomputed, type IngestResponse, LOG_LEVELS, type ListMemoryRequest, type ListMemoryResult, type ListOptions, type ListPromptsOptions, type ListPromptsResult, type LogLevelName, type LogLevelNumber, type LogRecord, type MemoryContent, type MemoryHistoryEntry, type MemoryHistoryEvent, type MemoryHit, type MemoryItem, type MemoryScope, type ModelsListResponse, type OpenRouterModel, type ParseInput, type ParseOptions, type PinoLike, type PlatformLogger, type PlatformLoggerMode, type PlatformLoggerOptions, type PostgresLike, type Prompt, type PublishRequest, RUN_ID_ATTRIBUTE, RUN_STEP_TYPES, type RagIngestProgress, type ReadableSpanLike, type Result, type RetrieveHit, type RetrieveRequest, type RetrieveRequestAutoEmbed, type RetrieveRequestPrecomputed, type RunStepType, RunStepsSpanProcessor, type RunStepsSpanProcessorOptions, STEP_TYPE_ATTRIBUTE, type SdkError, type SearchMemoryOptions, type SignedUrl, type SignedUrlOptions, type SpanContextLike, StackboneClient, type StorageBody, type StorageObject, type UpdateMemoryOptions, type UpdatePromptOptions, type UploadOptions, type VerifyOptions, aggregateRunCost, createClient, createPlatformLogger, defaultRunsDir };
|