@opengeni/api-router 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +1 -1
- package/dist/{chunk-SVBM6RM6.js → chunk-2JL5OXRE.js} +81 -4
- package/dist/chunk-2JL5OXRE.js.map +1 -0
- package/dist/index.js +38 -3
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/src/app.ts +67 -1
- package/src/http/auth.ts +1 -1
- package/src/index.ts +9 -4
- package/src/mcp/server.ts +5 -0
- package/src/observability.ts +31 -0
- package/src/routes/billing.ts +19 -1
- package/src/sandbox/auth-callout.ts +5 -1
- package/dist/chunk-SVBM6RM6.js.map +0 -1
package/dist/app.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "@opengeni/config";
|
|
7
7
|
import { ClientConfig } from "@opengeni/contracts";
|
|
8
8
|
import { createDocumentServices, indexDocumentNow } from "@opengeni/documents";
|
|
9
|
+
import { dbSql } from "@opengeni/db";
|
|
9
10
|
import { createObservability } from "@opengeni/observability";
|
|
10
11
|
import { createObjectStorage } from "@opengeni/storage";
|
|
11
12
|
import { WebStandardStreamableHTTPServerTransport as WebStandardStreamableHTTPServerTransport2 } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
@@ -929,6 +930,11 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, json) {
|
|
|
929
930
|
description: "Spawn a new agent session (a worker) with an initial message and optional goal, resources (e.g. repositories from github_repositories_list), tools, and workspace environment attachment. Environment attachment happens at creation only \u2014 it cannot be added to a running session \u2014 and requires the environments:use permission. When targetSandboxId names a machine, workingDir sets the working directory (cwd) the spawned session runs under on that machine.",
|
|
930
931
|
inputSchema: {
|
|
931
932
|
initialMessage: z4.string().min(1),
|
|
933
|
+
// Per-session agent persona/system instructions for the spawned worker
|
|
934
|
+
// (a per-agent-type prompt). Delivered system-level, composed AFTER the
|
|
935
|
+
// workspace persona; never shown in the worker's timeline. Trimmed,
|
|
936
|
+
// non-empty, max 32768 chars (re-validated by the contracts schema).
|
|
937
|
+
instructions: z4.string().min(1).max(32768).optional(),
|
|
932
938
|
goal: z4.unknown().optional(),
|
|
933
939
|
resources: z4.array(z4.unknown()).optional(),
|
|
934
940
|
tools: z4.array(z4.unknown()).optional(),
|
|
@@ -1362,7 +1368,7 @@ function isAuthExempt(c, settings) {
|
|
|
1362
1368
|
if (installExactPaths.has(path) || isInstallRedirectPath(path)) {
|
|
1363
1369
|
return true;
|
|
1364
1370
|
}
|
|
1365
|
-
if (settings.authAllowHealth && path === "/healthz") {
|
|
1371
|
+
if (settings.authAllowHealth && (path === "/healthz" || path === "/readyz")) {
|
|
1366
1372
|
return true;
|
|
1367
1373
|
}
|
|
1368
1374
|
if (settings.authAllowMetrics && path === "/metrics") {
|
|
@@ -3389,6 +3395,7 @@ async function handleCheckoutSessionCompleted(deps, event) {
|
|
|
3389
3395
|
stripeCreditAmountUsd: credit.amountUsd
|
|
3390
3396
|
}
|
|
3391
3397
|
});
|
|
3398
|
+
recordCreditMicrosMetric(deps, "topup", credit.amountMicros);
|
|
3392
3399
|
}
|
|
3393
3400
|
async function mirrorPaymentIntentCustomer(deps, event) {
|
|
3394
3401
|
const intent = event.data.object;
|
|
@@ -3421,18 +3428,23 @@ async function applyRefundDebit(deps, stripe, refund) {
|
|
|
3421
3428
|
if (!accountId) {
|
|
3422
3429
|
return;
|
|
3423
3430
|
}
|
|
3431
|
+
const idempotencyKey = `stripe:refund:${refund.id}`;
|
|
3432
|
+
if (await hasCreditLedgerEntry(deps.db, accountId, idempotencyKey)) {
|
|
3433
|
+
return;
|
|
3434
|
+
}
|
|
3424
3435
|
await applyCreditLedgerEntry(deps.db, {
|
|
3425
3436
|
accountId,
|
|
3426
3437
|
type: "credit_refund",
|
|
3427
3438
|
amountMicros: -centsToMicros(refund.amount),
|
|
3428
3439
|
sourceType: "stripe_refund",
|
|
3429
3440
|
sourceId: refund.id,
|
|
3430
|
-
idempotencyKey
|
|
3441
|
+
idempotencyKey,
|
|
3431
3442
|
metadata: {
|
|
3432
3443
|
stripeRefundId: refund.id,
|
|
3433
3444
|
stripePaymentIntentId: paymentIntentId(refund.payment_intent)
|
|
3434
3445
|
}
|
|
3435
3446
|
});
|
|
3447
|
+
recordCreditMicrosMetric(deps, "refund", centsToMicros(refund.amount));
|
|
3436
3448
|
}
|
|
3437
3449
|
async function holdDisputedCredits(deps, stripe, event) {
|
|
3438
3450
|
const dispute = event.data.object;
|
|
@@ -3487,6 +3499,17 @@ async function mirrorCustomer(deps, event, customer) {
|
|
|
3487
3499
|
email: typeof customer.email === "string" ? customer.email : null
|
|
3488
3500
|
});
|
|
3489
3501
|
}
|
|
3502
|
+
function recordCreditMicrosMetric(deps, kind, amountMicros) {
|
|
3503
|
+
if (amountMicros <= 0) {
|
|
3504
|
+
return;
|
|
3505
|
+
}
|
|
3506
|
+
deps.observability?.incrementCounter({
|
|
3507
|
+
name: "opengeni_credit_micros_total",
|
|
3508
|
+
help: "Total credit micros recorded by kind.",
|
|
3509
|
+
labels: { kind },
|
|
3510
|
+
amount: amountMicros
|
|
3511
|
+
});
|
|
3512
|
+
}
|
|
3490
3513
|
async function metadataForRefund(stripe, refund) {
|
|
3491
3514
|
if (Object.keys(refund.metadata ?? {}).length > 0) {
|
|
3492
3515
|
return refund.metadata;
|
|
@@ -6189,13 +6212,19 @@ function createApp(deps) {
|
|
|
6189
6212
|
service: deps.settings.serviceName,
|
|
6190
6213
|
environment: deps.settings.environment,
|
|
6191
6214
|
deploymentRevision: deps.settings.deploymentRevision,
|
|
6215
|
+
...deps.settings.serverVersion ? { serverVersion: deps.settings.serverVersion } : {},
|
|
6192
6216
|
ok: true
|
|
6193
6217
|
}));
|
|
6194
|
-
app.get("/
|
|
6218
|
+
app.get("/readyz", async (c) => {
|
|
6219
|
+
const result = await runReadinessChecks(readinessChecks(deps), 2e3);
|
|
6220
|
+
return c.json(result, result.ok ? 200 : 503);
|
|
6221
|
+
});
|
|
6222
|
+
app.get("/metrics", async (c) => c.text(await observability.prometheusMetrics(), 200, {
|
|
6195
6223
|
"content-type": "text/plain; version=0.0.4; charset=utf-8"
|
|
6196
6224
|
}));
|
|
6197
6225
|
app.get("/v1/config/client", (c) => c.json(ClientConfig.parse({
|
|
6198
6226
|
deploymentRevision: deps.settings.deploymentRevision,
|
|
6227
|
+
...deps.settings.serverVersion ? { serverVersion: deps.settings.serverVersion } : {},
|
|
6199
6228
|
defaultModel: deps.settings.openaiModel,
|
|
6200
6229
|
allowedModels: configuredAllowedModels(deps.settings),
|
|
6201
6230
|
// Provider-grouped model list for the picker. configuredModels() carries the
|
|
@@ -6278,8 +6307,56 @@ function httpStatusForError(error) {
|
|
|
6278
6307
|
}
|
|
6279
6308
|
return 500;
|
|
6280
6309
|
}
|
|
6310
|
+
function readinessChecks(deps) {
|
|
6311
|
+
return {
|
|
6312
|
+
db: deps.readinessChecks?.db ?? (async () => {
|
|
6313
|
+
await deps.db.execute(dbSql`select 1`);
|
|
6314
|
+
}),
|
|
6315
|
+
nats: deps.readinessChecks?.nats ?? (() => {
|
|
6316
|
+
if (deps.bus.isConnected && !deps.bus.isConnected()) {
|
|
6317
|
+
throw new Error("NATS is not connected");
|
|
6318
|
+
}
|
|
6319
|
+
}),
|
|
6320
|
+
temporal: deps.readinessChecks?.temporal ?? deps.workflowClient.check ?? (() => {
|
|
6321
|
+
throw new Error("Temporal readiness check unavailable");
|
|
6322
|
+
})
|
|
6323
|
+
};
|
|
6324
|
+
}
|
|
6325
|
+
async function runReadinessChecks(checks, timeoutMs) {
|
|
6326
|
+
const entries = await Promise.all(
|
|
6327
|
+
Object.entries(checks).map(async ([name, check]) => {
|
|
6328
|
+
try {
|
|
6329
|
+
await withTimeout(Promise.resolve().then(check), timeoutMs);
|
|
6330
|
+
return [name, { ok: true }];
|
|
6331
|
+
} catch (error) {
|
|
6332
|
+
return [name, { ok: false, error: error instanceof Error ? error.message : String(error) }];
|
|
6333
|
+
}
|
|
6334
|
+
})
|
|
6335
|
+
);
|
|
6336
|
+
const result = Object.fromEntries(entries);
|
|
6337
|
+
return {
|
|
6338
|
+
ok: Object.values(result).every((check) => check.ok),
|
|
6339
|
+
checks: result
|
|
6340
|
+
};
|
|
6341
|
+
}
|
|
6342
|
+
async function withTimeout(promise, timeoutMs) {
|
|
6343
|
+
let timer;
|
|
6344
|
+
try {
|
|
6345
|
+
return await Promise.race([
|
|
6346
|
+
promise,
|
|
6347
|
+
new Promise((_, reject) => {
|
|
6348
|
+
timer = setTimeout(() => reject(new Error(`readiness check timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
6349
|
+
})
|
|
6350
|
+
]);
|
|
6351
|
+
} finally {
|
|
6352
|
+
if (timer) {
|
|
6353
|
+
clearTimeout(timer);
|
|
6354
|
+
}
|
|
6355
|
+
}
|
|
6356
|
+
}
|
|
6281
6357
|
var routeLabelPatterns = [
|
|
6282
6358
|
{ pattern: /^\/healthz$/, label: "/healthz" },
|
|
6359
|
+
{ pattern: /^\/readyz$/, label: "/readyz" },
|
|
6283
6360
|
{ pattern: /^\/v1\/workspaces\/[^/]+\/codex\/connect\/start$/, label: "/v1/workspaces/:workspaceId/codex/connect/start" },
|
|
6284
6361
|
{ pattern: /^\/v1\/workspaces\/[^/]+\/codex\/connect\/poll$/, label: "/v1/workspaces/:workspaceId/codex/connect/poll" },
|
|
6285
6362
|
{ pattern: /^\/v1\/workspaces\/[^/]+\/codex\/status$/, label: "/v1/workspaces/:workspaceId/codex/status" },
|
|
@@ -6379,4 +6456,4 @@ export {
|
|
|
6379
6456
|
withDefaultEnabledCapabilityMcpTools,
|
|
6380
6457
|
workflowIdForSession3 as workflowIdForSession
|
|
6381
6458
|
};
|
|
6382
|
-
//# sourceMappingURL=chunk-
|
|
6459
|
+
//# sourceMappingURL=chunk-2JL5OXRE.js.map
|