@xopcai/xopc 0.0.22 → 0.0.24
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/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/agents-CiZMJZRp.js +216 -0
- package/dist/gateway/static/root/assets/agents-CiZMJZRp.js.map +1 -0
- package/dist/gateway/static/root/assets/apps-page-tZz69XM3.js +2 -0
- package/dist/gateway/static/root/assets/apps-page-tZz69XM3.js.map +1 -0
- package/dist/gateway/static/root/assets/{attachment-preview-renderer-CebH7fCz.js → attachment-preview-renderer-CxMJMbD2.js} +4 -4
- package/dist/gateway/static/root/assets/{attachment-preview-renderer-CebH7fCz.js.map → attachment-preview-renderer-CxMJMbD2.js.map} +1 -1
- package/dist/gateway/static/root/assets/{attachment-process-heavy-Dbf1--O6.js → attachment-process-heavy-EFXPGfWk.js} +6 -6
- package/dist/gateway/static/root/assets/{attachment-process-heavy-Dbf1--O6.js.map → attachment-process-heavy-EFXPGfWk.js.map} +1 -1
- package/dist/gateway/static/root/assets/{attachment-utils-core-Dt6UxMPV.js → attachment-utils-core-ECbeoa9H.js} +1 -1
- package/dist/gateway/static/root/assets/attachment-utils-core-ECbeoa9H.js.map +1 -0
- package/dist/gateway/static/root/assets/channels-settings-BAvk9-aK.js +9 -0
- package/dist/gateway/static/root/assets/{channels-settings-BGueHxMv.js.map → channels-settings-BAvk9-aK.js.map} +1 -1
- package/dist/gateway/static/root/assets/cn-BMCV0OMB.js +2 -0
- package/dist/gateway/static/root/assets/cn-BMCV0OMB.js.map +1 -0
- package/dist/gateway/static/root/assets/cron-page-CANqvhK7.js +2 -0
- package/dist/gateway/static/root/assets/{cron-page-DsVZzPqv.js.map → cron-page-CANqvhK7.js.map} +1 -1
- package/dist/gateway/static/root/assets/cron-utils-DyOO6TdN.js +3 -0
- package/dist/gateway/static/root/assets/{cron-utils-zbRs2yND.js.map → cron-utils-DyOO6TdN.js.map} +1 -1
- package/dist/gateway/static/root/assets/dist-Brod9LF3.js +2 -0
- package/dist/gateway/static/root/assets/{dist-CDA7gR_M.js.map → dist-Brod9LF3.js.map} +1 -1
- package/dist/gateway/static/root/assets/{docx-preview-DxcHM3sR.js → docx-preview-F-jKDMNv.js} +2 -2
- package/dist/gateway/static/root/assets/{docx-preview-DxcHM3sR.js.map → docx-preview-F-jKDMNv.js.map} +1 -1
- package/dist/gateway/static/root/assets/{excel-worksheet-utils-Dk66snKA.js → excel-worksheet-utils-DPfAinZn.js} +1 -1
- package/dist/gateway/static/root/assets/{excel-worksheet-utils-Dk66snKA.js.map → excel-worksheet-utils-DPfAinZn.js.map} +1 -1
- package/dist/gateway/static/root/assets/extension-debug-page-CDD7ozsC.js +2 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-CDLp4DAs.js.map → extension-debug-page-CDD7ozsC.js.map} +1 -1
- package/dist/gateway/static/root/assets/extension-page-UUFMjoWf.js +2 -0
- package/dist/gateway/static/root/assets/{extension-page-DwSCjzHO.js.map → extension-page-UUFMjoWf.js.map} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-CP9JNc4m.js +2 -0
- package/dist/gateway/static/root/assets/extension-settings-page-CP9JNc4m.js.map +1 -0
- package/dist/gateway/static/root/assets/index-BZvlG48D.js +150 -0
- package/dist/gateway/static/root/assets/index-BZvlG48D.js.map +1 -0
- package/dist/gateway/static/root/assets/index-DxkgyT8R.css +1 -0
- package/dist/gateway/static/root/assets/{jszip.min-DVUfmhpE.js → jszip.min-CL3dfyxs.js} +1 -1
- package/dist/gateway/static/root/assets/{jszip.min-DVUfmhpE.js.map → jszip.min-CL3dfyxs.js.map} +1 -1
- package/dist/gateway/static/root/assets/logs-page-Cr0eCGb4.js +2 -0
- package/dist/gateway/static/root/assets/{logs-page-ChJ0nsPh.js.map → logs-page-Cr0eCGb4.js.map} +1 -1
- package/dist/gateway/static/root/assets/{pdf--jE7rvON.js → pdf-CX6ji-QC.js} +1 -1
- package/dist/gateway/static/root/assets/{pdf--jE7rvON.js.map → pdf-CX6ji-QC.js.map} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DwLHN5GJ.js +2 -0
- package/dist/gateway/static/root/assets/{sessions-page-Cle4fPla.js.map → sessions-page-DwLHN5GJ.js.map} +1 -1
- package/dist/gateway/static/root/assets/settings-page-B3O3R0E4.js +2 -0
- package/dist/gateway/static/root/assets/settings-page-B3O3R0E4.js.map +1 -0
- package/dist/gateway/static/root/assets/skills-page-DgBYvH6B.js +3 -0
- package/dist/gateway/static/root/assets/{skills-page-B-smhcB2.js.map → skills-page-DgBYvH6B.js.map} +1 -1
- package/dist/gateway/static/root/assets/vendor-swr-B5fPo7KK.js +2 -0
- package/dist/gateway/static/root/assets/{vendor-swr-Dp4nzp5h.js.map → vendor-swr-B5fPo7KK.js.map} +1 -1
- package/dist/gateway/static/root/assets/{xlsx-DVk38js7.js → xlsx-CPtvfmVF.js} +1 -1
- package/dist/gateway/static/root/assets/{xlsx-DVk38js7.js.map → xlsx-CPtvfmVF.js.map} +1 -1
- package/dist/gateway/static/root/index.html +5 -4
- package/dist/package.js +1 -1
- package/dist/src/agent/image/tool-model-config.js +2 -2
- package/dist/src/agent/image/tool-model-config.js.map +1 -1
- package/dist/src/agent/tools/execute-code-tool.js +1 -1
- package/dist/src/agent/tools/execute-code-tool.js.map +1 -1
- package/dist/src/cli/commands/extension-dev.d.ts +2 -0
- package/dist/src/cli/commands/extension-dev.js +196 -0
- package/dist/src/cli/commands/extension-dev.js.map +1 -0
- package/dist/src/cli/commands/extension-marketplace.d.ts +4 -0
- package/dist/src/cli/commands/extension-marketplace.js +145 -0
- package/dist/src/cli/commands/extension-marketplace.js.map +1 -0
- package/dist/src/cli/commands/extension-pack.d.ts +2 -0
- package/dist/src/cli/commands/extension-pack.js +242 -0
- package/dist/src/cli/commands/extension-pack.js.map +1 -0
- package/dist/src/cli/commands/extension.js +13 -0
- package/dist/src/cli/commands/extension.js.map +1 -1
- package/dist/src/cli/index.js +5 -1
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/config/schema.js +1 -1
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/extensions/api.d.ts +6 -1
- package/dist/src/extensions/api.js +30 -0
- package/dist/src/extensions/api.js.map +1 -1
- package/dist/src/extensions/engine-check.d.ts +14 -0
- package/dist/src/extensions/engine-check.js +148 -0
- package/dist/src/extensions/engine-check.js.map +1 -0
- package/dist/src/extensions/loader.js +23 -0
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/marketplace.d.ts +24 -0
- package/dist/src/extensions/marketplace.js +98 -0
- package/dist/src/extensions/marketplace.js.map +1 -0
- package/dist/src/extensions/normalize-manifest.js +16 -4
- package/dist/src/extensions/normalize-manifest.js.map +1 -1
- package/dist/src/extensions/sdk/index.d.ts +2 -0
- package/dist/src/extensions/sdk/index.js +2 -1
- package/dist/src/extensions/sdk/index.js.map +1 -1
- package/dist/src/extensions/sdk/testing.d.ts +49 -3
- package/dist/src/extensions/sdk/testing.js +174 -5
- package/dist/src/extensions/sdk/testing.js.map +1 -1
- package/dist/src/extensions/types/core.d.ts +5 -0
- package/dist/src/extensions/types/manifest.d.ts +17 -0
- package/dist/src/extensions/when-context.d.ts +6 -0
- package/dist/src/extensions/when-context.js +28 -0
- package/dist/src/extensions/when-context.js.map +1 -0
- package/dist/src/extensions/when-expression.d.ts +11 -0
- package/dist/src/extensions/when-expression.js +215 -0
- package/dist/src/extensions/when-expression.js.map +1 -0
- package/dist/src/gateway/hono/app.js +1 -1
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +28 -0
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js.map +1 -1
- package/dist/src/providers/index.d.ts +6 -3
- package/dist/src/providers/index.js +12 -23
- package/dist/src/providers/index.js.map +1 -1
- package/package.json +2 -1
- package/dist/gateway/static/root/assets/agents-BcLv59-r.js +0 -71
- package/dist/gateway/static/root/assets/agents-BcLv59-r.js.map +0 -1
- package/dist/gateway/static/root/assets/apps-page-Bl-yxbQo.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-Bl-yxbQo.js.map +0 -1
- package/dist/gateway/static/root/assets/attachment-utils-core-Dt6UxMPV.js.map +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BGueHxMv.js +0 -9
- package/dist/gateway/static/root/assets/cron-page-DsVZzPqv.js +0 -2
- package/dist/gateway/static/root/assets/cron-utils-zbRs2yND.js +0 -3
- package/dist/gateway/static/root/assets/dist-CDA7gR_M.js +0 -2
- package/dist/gateway/static/root/assets/extension-debug-page-CDLp4DAs.js +0 -2
- package/dist/gateway/static/root/assets/extension-page-DwSCjzHO.js +0 -2
- package/dist/gateway/static/root/assets/extension-settings-page-Rdmxe24_.js +0 -2
- package/dist/gateway/static/root/assets/extension-settings-page-Rdmxe24_.js.map +0 -1
- package/dist/gateway/static/root/assets/index-D9Wmfh2f.css +0 -1
- package/dist/gateway/static/root/assets/index-DG8WvMbu.js +0 -150
- package/dist/gateway/static/root/assets/index-DG8WvMbu.js.map +0 -1
- package/dist/gateway/static/root/assets/logs-page-ChJ0nsPh.js +0 -2
- package/dist/gateway/static/root/assets/sessions-page-Cle4fPla.js +0 -2
- package/dist/gateway/static/root/assets/settings-page-Dyo2NYdy.js +0 -2
- package/dist/gateway/static/root/assets/settings-page-Dyo2NYdy.js.map +0 -1
- package/dist/gateway/static/root/assets/skills-page-B-smhcB2.js +0 -3
- package/dist/gateway/static/root/assets/vendor-swr-Dp4nzp5h.js +0 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"when-expression.js","names":[],"sources":["../../../src/extensions/when-expression.ts"],"sourcesContent":["/**\n * Boolean when-expressions for extension UI contributions (Phase 2).\n * Grammar: expression := term (('&&' | '||') term)*; term := '!' term | atom;\n * atom := variable (('==' | '!=') literal)? | '(' expression ')'\n */\n\nexport type WhenContext = Record<string, unknown>;\n\ntype Tok =\n | { k: 'AND' }\n | { k: 'OR' }\n | { k: 'NOT' }\n | { k: 'EQ' }\n | { k: 'NE' }\n | { k: 'LP' }\n | { k: 'RP' }\n | { k: 'IDENT'; v: string }\n | { k: 'STR'; v: string }\n | { k: 'NUM'; v: number }\n | { k: 'BOOL'; v: boolean }\n | { k: 'EOF' };\n\nfunction tokenize(input: string): Tok[] {\n const out: Tok[] = [];\n let i = 0;\n const s = input.trim();\n while (i < s.length) {\n const c = s[i]!;\n if (/\\s/.test(c)) {\n i++;\n continue;\n }\n if (s.slice(i, i + 2) === '&&') {\n out.push({ k: 'AND' });\n i += 2;\n continue;\n }\n if (s.slice(i, i + 2) === '||') {\n out.push({ k: 'OR' });\n i += 2;\n continue;\n }\n if (s.slice(i, i + 2) === '==') {\n out.push({ k: 'EQ' });\n i += 2;\n continue;\n }\n if (s.slice(i, i + 2) === '!=') {\n out.push({ k: 'NE' });\n i += 2;\n continue;\n }\n if (c === '(') {\n out.push({ k: 'LP' });\n i++;\n continue;\n }\n if (c === ')') {\n out.push({ k: 'RP' });\n i++;\n continue;\n }\n if (c === '!') {\n out.push({ k: 'NOT' });\n i++;\n continue;\n }\n if (c === \"'\" || c === '\"') {\n const q = c;\n i++;\n let buf = '';\n while (i < s.length) {\n const ch = s[i]!;\n if (ch === '\\\\' && i + 1 < s.length) {\n buf += s[i + 1]!;\n i += 2;\n continue;\n }\n if (ch === q) {\n i++;\n break;\n }\n buf += ch;\n i++;\n }\n out.push({ k: 'STR', v: buf });\n continue;\n }\n if (/[0-9]/.test(c) || (c === '-' && i + 1 < s.length && /[0-9]/.test(s[i + 1]!))) {\n let j = i + 1;\n while (j < s.length && /[0-9.]/.test(s[j]!)) j++;\n const n = Number(s.slice(i, j));\n out.push({ k: 'NUM', v: Number.isFinite(n) ? n : 0 });\n i = j;\n continue;\n }\n if (/[a-zA-Z_]/.test(c)) {\n let j = i + 1;\n while (j < s.length && /[a-zA-Z0-9_.]/.test(s[j]!)) j++;\n const word = s.slice(i, j);\n i = j;\n if (word === 'true') out.push({ k: 'BOOL', v: true });\n else if (word === 'false') out.push({ k: 'BOOL', v: false });\n else out.push({ k: 'IDENT', v: word });\n continue;\n }\n throw new Error(`Unexpected character in when-expression at ${i}: ${c}`);\n }\n out.push({ k: 'EOF' });\n return out;\n}\n\nfunction ctxLookup(ctx: WhenContext, key: string): unknown {\n if (key in ctx) return ctx[key];\n return undefined;\n}\n\nclass Parser {\n private i = 0;\n constructor(\n private readonly toks: Tok[],\n private readonly ctx: WhenContext,\n ) {}\n\n parse(): boolean {\n const v = this.parseOr();\n const tail = this.cur();\n if (tail.k !== 'EOF') {\n throw new Error(\n `Unexpected tokens after expression (at ${this.i}: ${tail.k}${'v' in tail ? ` ${(tail as { v: unknown }).v}` : ''})`,\n );\n }\n return v;\n }\n\n private cur(): Tok {\n return this.toks[this.i] ?? { k: 'EOF' };\n }\n\n private parseOr(): boolean {\n let v = this.parseAnd();\n while (this.cur().k === 'OR') {\n this.i++;\n const rhs = this.parseAnd();\n v = v || rhs;\n }\n return v;\n }\n\n private parseAnd(): boolean {\n let v = this.parseUnary();\n while (this.cur().k === 'AND') {\n this.i++;\n const rhs = this.parseUnary();\n v = v && rhs;\n }\n return v;\n }\n\n private parseUnary(): boolean {\n if (this.cur().k === 'NOT') {\n this.i++;\n return !this.parseUnary();\n }\n return this.parsePrimary();\n }\n\n private parsePrimary(): boolean {\n const t = this.cur();\n if (t.k === 'LP') {\n this.i++;\n const inner = this.parseOr();\n if (this.cur().k !== 'RP') throw new Error('Expected )');\n this.i++;\n return inner;\n }\n return this.parseAtom();\n }\n\n private parseAtom(): boolean {\n const left = this.readAtomValue();\n const op = this.cur();\n if (op.k === 'EQ' || op.k === 'NE') {\n this.i++;\n const right = this.readAtomValue();\n const eq = valuesLooselyEqual(left, right);\n return op.k === 'EQ' ? eq : !eq;\n }\n return isTruthyWhen(left);\n }\n\n private readAtomValue(): unknown {\n const t = this.cur();\n if (t.k === 'IDENT') {\n this.i++;\n return ctxLookup(this.ctx, t.v);\n }\n if (t.k === 'STR') {\n this.i++;\n return t.v;\n }\n if (t.k === 'NUM') {\n this.i++;\n return t.v;\n }\n if (t.k === 'BOOL') {\n this.i++;\n return t.v;\n }\n throw new Error('Expected value in when-expression');\n }\n}\n\nfunction valuesLooselyEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a == null || b == null) return a === b;\n if (typeof a === 'boolean' || typeof b === 'boolean') return Boolean(a) === Boolean(b);\n if (typeof a === 'number' && typeof b === 'number') return a === b;\n return String(a) === String(b);\n}\n\nfunction isTruthyWhen(v: unknown): boolean {\n if (typeof v === 'boolean') return v;\n if (typeof v === 'number') return v !== 0;\n if (typeof v === 'string') return v.length > 0;\n return v != null;\n}\n\n/**\n * Evaluate a when-expression string against a flat context object.\n * Unknown variables are treated as falsey for boolean tests; missing keys are undefined.\n */\nexport function evaluateWhenExpression(expr: string, ctx: WhenContext): boolean {\n const s = expr.trim();\n if (!s) return true;\n const toks = tokenize(s);\n return new Parser(toks, ctx).parse();\n}\n"],"mappings":"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"}
|
|
@@ -64,7 +64,7 @@ function createHonoApp(config) {
|
|
|
64
64
|
c.header("X-Content-Type-Options", "nosniff");
|
|
65
65
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
66
66
|
c.header("X-XSS-Protection", "1; mode=block");
|
|
67
|
-
c.header("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
|
|
67
|
+
c.header("Permissions-Policy", "camera=(), microphone=(self), geolocation=()");
|
|
68
68
|
c.header("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'");
|
|
69
69
|
}));
|
|
70
70
|
app.use("/api/skills/upload", bodyLimit({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","names":[],"sources":["../../../../src/gateway/hono/app.ts"],"sourcesContent":["import { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { createMiddleware } from 'hono/factory';\nimport { bodyLimit } from 'hono/body-limit';\n\nimport { createFixedWindowRateLimiter } from '../../infra/rate-limit.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { GatewayService } from '../service.js';\nimport { maxWebchatAgentRequestBodyBytes } from '../chat-limits.js';\nimport { auth } from './middleware/auth.js';\nimport { logContextMiddleware } from './middleware/log-context.js';\nimport { logger } from './middleware/logger.js';\nimport { registerPublicExtensionAssetRoutes } from './routes/auth-registry-extensions.js';\nimport { registerAuthenticatedRoutes } from './routes/index.js';\nimport { registerPublicGatewayRoutes } from './routes/public-gateway.js';\n\nconst log = createLogger('HonoApp');\n\nexport interface HonoAppConfig {\n service: GatewayService;\n token?: string;\n}\n\n/**\n * Extension sandbox HTML under `/api/extensions/:id/assets/*` ships its own CSP\n * (`frame-ancestors 'self'`). The global gateway middleware must not overwrite it\n * with `frame-ancestors 'none'` / `X-Frame-Options: DENY`, or the console cannot embed iframes.\n */\nexport function isExtensionGatewayUiAssetPath(path: string): boolean {\n return /^\\/api\\/extensions\\/[^/]+\\/assets\\//.test(path);\n}\n\nexport function createHonoApp(config: HonoAppConfig): Hono {\n const { service, token } = config;\n const app = new Hono();\n\n const gatewayPort = service.currentConfig.gateway.port ?? 18790;\n const configuredOrigins = service.currentConfig.gateway.corsOrigins;\n\n let corsOrigin: string | string[];\n if (configuredOrigins && configuredOrigins.length > 0) {\n corsOrigin = configuredOrigins;\n } else {\n corsOrigin = [\n `http://localhost:${gatewayPort}`,\n `http://127.0.0.1:${gatewayPort}`,\n 'http://localhost:3000',\n 'http://127.0.0.1:3000',\n ];\n }\n\n const CORS_OPTIONS = {\n origin: corsOrigin,\n allowMethods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Authorization', 'Accept', 'X-Session-Id', 'Last-Event-ID'],\n credentials: true,\n maxAge: 86400,\n };\n\n app.use(logContextMiddleware());\n app.use(logger());\n app.use(cors(CORS_OPTIONS));\n\n app.use(createMiddleware(async (c, next) => {\n await next();\n if (isExtensionGatewayUiAssetPath(c.req.path)) {\n return;\n }\n c.header('X-Frame-Options', 'DENY');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Referrer-Policy', 'strict-origin-when-cross-origin');\n c.header('X-XSS-Protection', '1; mode=block');\n c.header('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');\n c.header(\n 'Content-Security-Policy',\n \"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'\",\n );\n }));\n\n app.use('/api/skills/upload', bodyLimit({\n maxSize: 10 * 1024 * 1024,\n onError: (c) => {\n return c.json({ error: 'Skill package too large', maxSize: '10MB' }, 413);\n },\n }));\n\n const DEFAULT_API_BODY_MAX = 1 * 1024 * 1024;\n const WEBCHAT_AGENT_BODY_MAX = maxWebchatAgentRequestBodyBytes();\n\n app.use('/api/*', async (c, next) => {\n const maxSize = c.req.path === '/api/agent' ? WEBCHAT_AGENT_BODY_MAX : DEFAULT_API_BODY_MAX;\n const maxSizeMb = Math.ceil(maxSize / (1024 * 1024));\n return bodyLimit({\n maxSize,\n onError: (ctx) =>\n ctx.json({ error: 'Request body too large', maxSize: `${maxSizeMb}MB` }, 413),\n })(c, next);\n });\n\n registerPublicGatewayRoutes(app, service);\n\n // Extension UI assets are served without auth: sandboxed iframes (no allow-same-origin)\n // have an opaque origin of `null` and cannot forward the ?token= from the parent HTML URL.\n // Security is enforced by the strict CSP (frame-ancestors 'self') on every response.\n registerPublicExtensionAssetRoutes(app, service);\n\n const authenticated = new Hono();\n authenticated.use(\n auth({\n token,\n getGatewayAuth: () => service.currentConfig.gateway?.auth,\n }),\n );\n\n const strictRateLimiter = new Map<string, ReturnType<typeof createFixedWindowRateLimiter>>();\n\n const RATE_LIMIT_CLEANUP_INTERVAL = 5 * 60 * 1000;\n setInterval(() => {\n for (const [ip, limiter] of strictRateLimiter.entries()) {\n const result = limiter.consume();\n if (result.remaining === 9) {\n strictRateLimiter.delete(ip);\n }\n }\n }, RATE_LIMIT_CLEANUP_INTERVAL);\n\n const strictRateLimitMiddleware = createMiddleware(async (c, next) => {\n /*\n const clientIp = c.req.header('x-forwarded-for')?.split(',')[0]?.trim()\n ?? c.req.header('x-real-ip')\n ?? 'unknown';\n\n let limiter = strictRateLimiter.get(clientIp);\n if (!limiter) {\n limiter = createFixedWindowRateLimiter({ maxRequests: 10, windowMs: 60_000 });\n strictRateLimiter.set(clientIp, limiter);\n }\n\n const result = limiter.consume();\n if (!result.allowed) {\n c.header('Retry-After', String(Math.ceil(result.retryAfterMs / 1000)));\n return c.json({ error: 'Too many requests' }, 429);\n }\n\n c.header('X-RateLimit-Remaining', String(result.remaining));\n */\n await next();\n });\n\n const sseConfig = {\n service,\n maxSseConnections: service.currentConfig.gateway.maxSseConnections,\n };\n\n registerAuthenticatedRoutes(authenticated, {\n service,\n strictRateLimitMiddleware,\n sseConfig,\n });\n\n app.route('/', authenticated);\n\n app.notFound((c) => {\n return c.json({ error: 'Not found' }, 404);\n });\n\n app.onError((err, c) => {\n log.error({ err }, 'Hono error');\n return c.json({ error: 'Internal server error' }, 500);\n });\n\n return app;\n}\n"],"mappings":";;;;;;;;;;;;;;aAMqD;AAUrD,MAAM,MAAM,aAAa,UAAU;;;;;;AAYnC,SAAgB,8BAA8B,MAAuB;AACnE,QAAO,sCAAsC,KAAK,KAAK;;AAGzD,SAAgB,cAAc,QAA6B;CACzD,MAAM,EAAE,SAAS,UAAU;CAC3B,MAAM,MAAM,IAAI,MAAM;CAEtB,MAAM,cAAc,QAAQ,cAAc,QAAQ,QAAQ;CAC1D,MAAM,oBAAoB,QAAQ,cAAc,QAAQ;CAExD,IAAI;AACJ,KAAI,qBAAqB,kBAAkB,SAAS,EAClD,cAAa;KAEb,cAAa;EACX,oBAAoB;EACpB,oBAAoB;EACpB;EACA;EACD;CAGH,MAAM,eAAe;EACnB,QAAQ;EACR,cAAc;GAAC;GAAO;GAAQ;GAAS;GAAU;GAAU;EAC3D,cAAc;GAAC;GAAgB;GAAiB;GAAU;GAAgB;GAAgB;EAC1F,aAAa;EACb,QAAQ;EACT;AAED,KAAI,IAAI,sBAAsB,CAAC;AAC/B,KAAI,IAAI,QAAQ,CAAC;AACjB,KAAI,IAAI,KAAK,aAAa,CAAC;AAE3B,KAAI,IAAI,iBAAiB,OAAO,GAAG,SAAS;AAC1C,QAAM,MAAM;AACZ,MAAI,8BAA8B,EAAE,IAAI,KAAK,CAC3C;AAEF,IAAE,OAAO,mBAAmB,OAAO;AACnC,IAAE,OAAO,0BAA0B,UAAU;AAC7C,IAAE,OAAO,mBAAmB,kCAAkC;AAC9D,IAAE,OAAO,oBAAoB,gBAAgB;
|
|
1
|
+
{"version":3,"file":"app.js","names":[],"sources":["../../../../src/gateway/hono/app.ts"],"sourcesContent":["import { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { createMiddleware } from 'hono/factory';\nimport { bodyLimit } from 'hono/body-limit';\n\nimport { createFixedWindowRateLimiter } from '../../infra/rate-limit.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { GatewayService } from '../service.js';\nimport { maxWebchatAgentRequestBodyBytes } from '../chat-limits.js';\nimport { auth } from './middleware/auth.js';\nimport { logContextMiddleware } from './middleware/log-context.js';\nimport { logger } from './middleware/logger.js';\nimport { registerPublicExtensionAssetRoutes } from './routes/auth-registry-extensions.js';\nimport { registerAuthenticatedRoutes } from './routes/index.js';\nimport { registerPublicGatewayRoutes } from './routes/public-gateway.js';\n\nconst log = createLogger('HonoApp');\n\nexport interface HonoAppConfig {\n service: GatewayService;\n token?: string;\n}\n\n/**\n * Extension sandbox HTML under `/api/extensions/:id/assets/*` ships its own CSP\n * (`frame-ancestors 'self'`). The global gateway middleware must not overwrite it\n * with `frame-ancestors 'none'` / `X-Frame-Options: DENY`, or the console cannot embed iframes.\n */\nexport function isExtensionGatewayUiAssetPath(path: string): boolean {\n return /^\\/api\\/extensions\\/[^/]+\\/assets\\//.test(path);\n}\n\nexport function createHonoApp(config: HonoAppConfig): Hono {\n const { service, token } = config;\n const app = new Hono();\n\n const gatewayPort = service.currentConfig.gateway.port ?? 18790;\n const configuredOrigins = service.currentConfig.gateway.corsOrigins;\n\n let corsOrigin: string | string[];\n if (configuredOrigins && configuredOrigins.length > 0) {\n corsOrigin = configuredOrigins;\n } else {\n corsOrigin = [\n `http://localhost:${gatewayPort}`,\n `http://127.0.0.1:${gatewayPort}`,\n 'http://localhost:3000',\n 'http://127.0.0.1:3000',\n ];\n }\n\n const CORS_OPTIONS = {\n origin: corsOrigin,\n allowMethods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Authorization', 'Accept', 'X-Session-Id', 'Last-Event-ID'],\n credentials: true,\n maxAge: 86400,\n };\n\n app.use(logContextMiddleware());\n app.use(logger());\n app.use(cors(CORS_OPTIONS));\n\n app.use(createMiddleware(async (c, next) => {\n await next();\n if (isExtensionGatewayUiAssetPath(c.req.path)) {\n return;\n }\n c.header('X-Frame-Options', 'DENY');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Referrer-Policy', 'strict-origin-when-cross-origin');\n c.header('X-XSS-Protection', '1; mode=block');\n // microphone=(self): allow same-origin chat voice (composer). microphone=() breaks packaged Electron loading the gateway SPA.\n c.header('Permissions-Policy', 'camera=(), microphone=(self), geolocation=()');\n c.header(\n 'Content-Security-Policy',\n \"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'\",\n );\n }));\n\n app.use('/api/skills/upload', bodyLimit({\n maxSize: 10 * 1024 * 1024,\n onError: (c) => {\n return c.json({ error: 'Skill package too large', maxSize: '10MB' }, 413);\n },\n }));\n\n const DEFAULT_API_BODY_MAX = 1 * 1024 * 1024;\n const WEBCHAT_AGENT_BODY_MAX = maxWebchatAgentRequestBodyBytes();\n\n app.use('/api/*', async (c, next) => {\n const maxSize = c.req.path === '/api/agent' ? WEBCHAT_AGENT_BODY_MAX : DEFAULT_API_BODY_MAX;\n const maxSizeMb = Math.ceil(maxSize / (1024 * 1024));\n return bodyLimit({\n maxSize,\n onError: (ctx) =>\n ctx.json({ error: 'Request body too large', maxSize: `${maxSizeMb}MB` }, 413),\n })(c, next);\n });\n\n registerPublicGatewayRoutes(app, service);\n\n // Extension UI assets are served without auth: sandboxed iframes (no allow-same-origin)\n // have an opaque origin of `null` and cannot forward the ?token= from the parent HTML URL.\n // Security is enforced by the strict CSP (frame-ancestors 'self') on every response.\n registerPublicExtensionAssetRoutes(app, service);\n\n const authenticated = new Hono();\n authenticated.use(\n auth({\n token,\n getGatewayAuth: () => service.currentConfig.gateway?.auth,\n }),\n );\n\n const strictRateLimiter = new Map<string, ReturnType<typeof createFixedWindowRateLimiter>>();\n\n const RATE_LIMIT_CLEANUP_INTERVAL = 5 * 60 * 1000;\n setInterval(() => {\n for (const [ip, limiter] of strictRateLimiter.entries()) {\n const result = limiter.consume();\n if (result.remaining === 9) {\n strictRateLimiter.delete(ip);\n }\n }\n }, RATE_LIMIT_CLEANUP_INTERVAL);\n\n const strictRateLimitMiddleware = createMiddleware(async (c, next) => {\n /*\n const clientIp = c.req.header('x-forwarded-for')?.split(',')[0]?.trim()\n ?? c.req.header('x-real-ip')\n ?? 'unknown';\n\n let limiter = strictRateLimiter.get(clientIp);\n if (!limiter) {\n limiter = createFixedWindowRateLimiter({ maxRequests: 10, windowMs: 60_000 });\n strictRateLimiter.set(clientIp, limiter);\n }\n\n const result = limiter.consume();\n if (!result.allowed) {\n c.header('Retry-After', String(Math.ceil(result.retryAfterMs / 1000)));\n return c.json({ error: 'Too many requests' }, 429);\n }\n\n c.header('X-RateLimit-Remaining', String(result.remaining));\n */\n await next();\n });\n\n const sseConfig = {\n service,\n maxSseConnections: service.currentConfig.gateway.maxSseConnections,\n };\n\n registerAuthenticatedRoutes(authenticated, {\n service,\n strictRateLimitMiddleware,\n sseConfig,\n });\n\n app.route('/', authenticated);\n\n app.notFound((c) => {\n return c.json({ error: 'Not found' }, 404);\n });\n\n app.onError((err, c) => {\n log.error({ err }, 'Hono error');\n return c.json({ error: 'Internal server error' }, 500);\n });\n\n return app;\n}\n"],"mappings":";;;;;;;;;;;;;;aAMqD;AAUrD,MAAM,MAAM,aAAa,UAAU;;;;;;AAYnC,SAAgB,8BAA8B,MAAuB;AACnE,QAAO,sCAAsC,KAAK,KAAK;;AAGzD,SAAgB,cAAc,QAA6B;CACzD,MAAM,EAAE,SAAS,UAAU;CAC3B,MAAM,MAAM,IAAI,MAAM;CAEtB,MAAM,cAAc,QAAQ,cAAc,QAAQ,QAAQ;CAC1D,MAAM,oBAAoB,QAAQ,cAAc,QAAQ;CAExD,IAAI;AACJ,KAAI,qBAAqB,kBAAkB,SAAS,EAClD,cAAa;KAEb,cAAa;EACX,oBAAoB;EACpB,oBAAoB;EACpB;EACA;EACD;CAGH,MAAM,eAAe;EACnB,QAAQ;EACR,cAAc;GAAC;GAAO;GAAQ;GAAS;GAAU;GAAU;EAC3D,cAAc;GAAC;GAAgB;GAAiB;GAAU;GAAgB;GAAgB;EAC1F,aAAa;EACb,QAAQ;EACT;AAED,KAAI,IAAI,sBAAsB,CAAC;AAC/B,KAAI,IAAI,QAAQ,CAAC;AACjB,KAAI,IAAI,KAAK,aAAa,CAAC;AAE3B,KAAI,IAAI,iBAAiB,OAAO,GAAG,SAAS;AAC1C,QAAM,MAAM;AACZ,MAAI,8BAA8B,EAAE,IAAI,KAAK,CAC3C;AAEF,IAAE,OAAO,mBAAmB,OAAO;AACnC,IAAE,OAAO,0BAA0B,UAAU;AAC7C,IAAE,OAAO,mBAAmB,kCAAkC;AAC9D,IAAE,OAAO,oBAAoB,gBAAgB;AAE7C,IAAE,OAAO,sBAAsB,+CAA+C;AAC9E,IAAE,OACA,2BACA,0KACD;GACD,CAAC;AAEH,KAAI,IAAI,sBAAsB,UAAU;EACtC,SAAS,KAAK,OAAO;EACrB,UAAU,MAAM;AACd,UAAO,EAAE,KAAK;IAAE,OAAO;IAA2B,SAAS;IAAQ,EAAE,IAAI;;EAE5E,CAAC,CAAC;CAEH,MAAM,uBAAuB,IAAI,OAAO;CACxC,MAAM,yBAAyB,iCAAiC;AAEhE,KAAI,IAAI,UAAU,OAAO,GAAG,SAAS;EACnC,MAAM,UAAU,EAAE,IAAI,SAAS,eAAe,yBAAyB;EACvE,MAAM,YAAY,KAAK,KAAK,WAAW,OAAO,MAAM;AACpD,SAAO,UAAU;GACf;GACA,UAAU,QACR,IAAI,KAAK;IAAE,OAAO;IAA0B,SAAS,GAAG,UAAU;IAAK,EAAE,IAAI;GAChF,CAAC,CAAC,GAAG,KAAK;GACX;AAEF,6BAA4B,KAAK,QAAQ;AAKzC,oCAAmC,KAAK,QAAQ;CAEhD,MAAM,gBAAgB,IAAI,MAAM;AAChC,eAAc,IACZ,KAAK;EACH;EACA,sBAAsB,QAAQ,cAAc,SAAS;EACtD,CAAC,CACH;CAED,MAAM,oCAAoB,IAAI,KAA8D;AAG5F,mBAAkB;AAChB,OAAK,MAAM,CAAC,IAAI,YAAY,kBAAkB,SAAS,CAErD,KADe,QAAQ,SACb,CAAC,cAAc,EACvB,mBAAkB,OAAO,GAAG;IALE,MAAS,IAQd;AA8B/B,6BAA4B,eAAe;EACzC;EACA,2BA9BgC,iBAAiB,OAAO,GAAG,SAAS;AAoBpE,SAAM,MAAM;IAUa;EACzB,WAAA;GAPA;GACA,mBAAmB,QAAQ,cAAc,QAAQ;GAMxC;EACV,CAAC;AAEF,KAAI,MAAM,KAAK,cAAc;AAE7B,KAAI,UAAU,MAAM;AAClB,SAAO,EAAE,KAAK,EAAE,OAAO,aAAa,EAAE,IAAI;GAC1C;AAEF,KAAI,SAAS,KAAK,MAAM;AACtB,MAAI,MAAM,EAAE,KAAK,EAAE,aAAa;AAChC,SAAO,EAAE,KAAK,EAAE,OAAO,yBAAyB,EAAE,IAAI;GACtD;AAEF,QAAO"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getAllModels, getAvailableModels, init_providers } from "../../../providers/index.js";
|
|
2
2
|
import { ActivationPlanner } from "../../../extensions/activation-planner.js";
|
|
3
3
|
import { mergeActivationContext } from "../../../extensions/activation-context.js";
|
|
4
|
+
import { buildWhenContextSnapshot } from "../../../extensions/when-context.js";
|
|
5
|
+
import { fetchRegistry, listExtensions, searchExtensions } from "../../../extensions/marketplace.js";
|
|
4
6
|
import { createOAuthHandler } from "../oauth.js";
|
|
5
7
|
import { createOAuthAsyncHandler } from "../oauth-async.js";
|
|
6
8
|
import { extensionAssetMimeType } from "../lib/extension-assets.js";
|
|
@@ -159,6 +161,7 @@ function registerAuthRegistryExtensionsRoutes(authenticated, deps) {
|
|
|
159
161
|
active: activeIds.has(ext.id),
|
|
160
162
|
activationEligible: activationEligibleIds.has(ext.id),
|
|
161
163
|
hasUi: Boolean(ext.manifest.ui),
|
|
164
|
+
hasConfigSchema: Boolean(ext.manifest.configSchema),
|
|
162
165
|
ui: ext.manifest.ui ? {
|
|
163
166
|
icon: ext.manifest.ui.icon,
|
|
164
167
|
permissions: ext.manifest.ui.permissions,
|
|
@@ -254,6 +257,31 @@ function registerAuthRegistryExtensionsRoutes(authenticated, deps) {
|
|
|
254
257
|
await saveExtensionStore(namespace, config);
|
|
255
258
|
return c.json({ ok: true });
|
|
256
259
|
});
|
|
260
|
+
authenticated.get("/api/context", (c) => {
|
|
261
|
+
const loader = service.getExtensionLoader();
|
|
262
|
+
const snapshot = buildWhenContextSnapshot(service.currentConfig, loader);
|
|
263
|
+
return c.json(snapshot);
|
|
264
|
+
});
|
|
265
|
+
authenticated.get("/api/marketplace", async (c) => {
|
|
266
|
+
const q = c.req.query("q");
|
|
267
|
+
const category = c.req.query("category");
|
|
268
|
+
try {
|
|
269
|
+
let extensions;
|
|
270
|
+
if (typeof q === "string" && q.trim()) extensions = await searchExtensions(q.trim());
|
|
271
|
+
else if (typeof category === "string" && category.trim()) extensions = await listExtensions(category.trim());
|
|
272
|
+
else extensions = (await fetchRegistry()).extensions;
|
|
273
|
+
return c.json({
|
|
274
|
+
ok: true,
|
|
275
|
+
extensions
|
|
276
|
+
});
|
|
277
|
+
} catch (err) {
|
|
278
|
+
return c.json({
|
|
279
|
+
ok: false,
|
|
280
|
+
extensions: [],
|
|
281
|
+
error: err instanceof Error ? err.message : "marketplace fetch failed"
|
|
282
|
+
}, 500);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
257
285
|
authenticated.post("/api/registry/reload", async (c) => {
|
|
258
286
|
try {
|
|
259
287
|
await service.reloadConfig();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-registry-extensions.js","names":[],"sources":["../../../../../src/gateway/hono/routes/auth-registry-extensions.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport { existsSync, readFileSync, statSync } from 'node:fs';\nimport { relative, resolve } from 'node:path';\n\nimport type { Config as SurfaceConfig } from '../../../config/config-surface.js';\nimport type { GatewayService } from '../../service.js';\nimport { mergeActivationContext } from '../../../extensions/activation-context.js';\nimport { ActivationPlanner } from '../../../extensions/activation-planner.js';\nimport { getAllModels, getAvailableModels, type Model, type Api } from '../../../providers/index.js';\nimport { createOAuthHandler, loadOAuthCredentialsToCache } from '../oauth.js';\nimport { createOAuthAsyncHandler } from '../oauth-async.js';\nimport { extensionAssetMimeType } from '../lib/extension-assets.js';\nimport { loadExtensionStore, saveExtensionStore } from '../lib/extension-store.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst EXTENSION_ASSET_CSP =\n \"default-src 'self'; \" +\n \"script-src 'self' 'unsafe-inline'; \" +\n \"style-src 'self' 'unsafe-inline'; \" +\n \"img-src 'self' data: blob:; \" +\n \"connect-src 'none'; \" +\n \"frame-ancestors 'self'; \" +\n \"frame-src 'none'; \" +\n \"base-uri 'none'; \" +\n \"object-src 'none'; \" +\n \"form-action 'none'\";\n\nfunction rewriteExtensionAssetHtml(html: string, extensionId: string, assetPath: string): string {\n const assetDir = assetPath.includes('/') ? assetPath.slice(0, assetPath.lastIndexOf('/') + 1) : '';\n const assetBase = `/api/extensions/${extensionId}/assets/${assetDir}`;\n\n return html\n .replace(/(<script\\b[^>]*?\\ssrc=)([\"'])(\\.\\/)?([^\"']+)\\2/gi, (_match, tag, quote, _dot, file) => {\n const isAbsolute =\n file.startsWith('/') || file.startsWith('http://') || file.startsWith('https://');\n const resolvedSrc = isAbsolute ? file : `${assetBase}${file}`;\n return `${tag}${quote}${resolvedSrc}${quote} crossorigin=\"anonymous\"`;\n })\n .replace(/(<link\\b[^>]*?\\shref=)([\"'])(\\.\\/)?([^\"']+)\\2/gi, (_match, tag, quote, _dot, file) => {\n const isAbsolute =\n file.startsWith('/') || file.startsWith('http://') || file.startsWith('https://');\n const resolvedHref = isAbsolute ? file : `${assetBase}${file}`;\n return `${tag}${quote}${resolvedHref}${quote}`;\n });\n}\n\n/**\n * Register extension UI asset routes on the public (unauthenticated) app.\n *\n * Sandboxed iframes (`sandbox=\"allow-scripts …\"` without `allow-same-origin`) have an\n * opaque origin of `null`, so sub-resource requests from inside the iframe cannot\n * carry the `?token=` query parameter that was on the parent HTML URL. Putting these\n * routes behind the auth middleware therefore causes every JS/CSS asset to return 401.\n *\n * Security is maintained by the strict Content-Security-Policy returned with every\n * asset (`frame-ancestors 'self'`), which prevents any page other than the gateway\n * console itself from embedding the extension iframes.\n */\nexport function registerPublicExtensionAssetRoutes(app: Hono, service: GatewayService): void {\n app.get('/api/extensions/:id/assets/*', async (c) => {\n const extensionId = c.req.param('id');\n const loader = service.getExtensionLoader();\n if (!loader) {\n return c.json({ error: 'Extensions unavailable' }, 503);\n }\n\n const discovered = loader.discoverExtensions();\n const ext = discovered.find((e) => e.id === extensionId);\n if (!ext || !ext.manifest.ui) {\n return c.json({ error: 'Extension not found or has no UI' }, 404);\n }\n\n const prefix = `/api/extensions/${extensionId}/assets/`;\n const assetPathEncoded = c.req.path.startsWith(prefix) ? c.req.path.slice(prefix.length) : '';\n let assetPath = assetPathEncoded;\n try {\n assetPath = decodeURIComponent(assetPathEncoded);\n } catch {\n return c.json({ error: 'Invalid asset path' }, 400);\n }\n\n if (!assetPath || assetPath.includes('..')) {\n return c.json({ error: 'Invalid asset path' }, 400);\n }\n\n const root = resolve(ext.path);\n const fullPath = resolve(root, assetPath);\n const rel = relative(root, fullPath);\n if (rel.startsWith('..') || rel === '') {\n return c.json({ error: 'Path traversal denied' }, 403);\n }\n\n if (!existsSync(fullPath) || !statSync(fullPath).isFile()) {\n return c.json({ error: 'Not found' }, 404);\n }\n\n const rawContent = readFileSync(fullPath);\n const mimeType = extensionAssetMimeType(assetPath);\n\n const body: string | Uint8Array = mimeType.startsWith('text/html')\n ? rewriteExtensionAssetHtml(rawContent.toString('utf-8'), extensionId, assetPath)\n : new Uint8Array(rawContent);\n\n return new Response(body, {\n status: 200,\n headers: {\n 'Content-Type': mimeType,\n 'Content-Security-Policy': EXTENSION_ASSET_CSP,\n 'Cache-Control': 'no-store',\n 'X-Content-Type-Options': 'nosniff',\n 'Access-Control-Allow-Origin': 'null',\n },\n });\n });\n}\n\nexport function registerAuthRegistryExtensionsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n // ========== Auth API (/api/auth) ==========\n\n // GET /api/auth/token - Get current gateway token\n authenticated.get('/api/auth/token', (c) => {\n const authToken = service.getAuthToken();\n return c.json({ \n ok: true, \n payload: { \n token: authToken,\n mode: service.getAuthMode(),\n } \n });\n });\n\n // POST /api/auth/token/refresh - Generate new gateway token\n authenticated.post('/api/auth/token/refresh', async (c) => {\n try {\n const newToken = await service.refreshAuthToken();\n return c.json({ \n ok: true, \n payload: { \n token: newToken,\n message: 'Token refreshed successfully. Please update your client configuration.'\n } \n });\n } catch (err) {\n return c.json({ \n ok: false, \n error: err instanceof Error ? err.message : 'Failed to refresh token' \n }, 500);\n }\n });\n\n // ========== OAuth API (/api/auth/oauth) ==========\n authenticated.route('/api/auth/oauth', createOAuthHandler(service));\n\n // ========== Async OAuth API (/api/auth/oauth-async) ==========\n authenticated.route('/api/auth/oauth-async', createOAuthAsyncHandler(service));\n\n // Load OAuth credentials from config into cache on startup\n loadOAuthCredentialsToCache(service);\n\n // ========== Registry API ==========\n \n // GET /api/registry - Full registry for frontend\n authenticated.get('/api/registry', async (c) => {\n const allModels = getAllModels();\n const availableModels = await getAvailableModels();\n const configured = new Set(availableModels.map(m => `${m.provider}/${m.id}`));\n \n // Group models by provider\n const providerMap = new Map<string, Model<Api>[]>();\n for (const model of allModels) {\n const list = providerMap.get(model.provider) ?? [];\n list.push(model);\n providerMap.set(model.provider, list);\n }\n \n return c.json({\n ok: true,\n payload: {\n version: 'pi-ai',\n providers: Array.from(providerMap.entries()).map(([id, models]) => ({\n id,\n name: id.charAt(0).toUpperCase() + id.slice(1),\n configured: models.some(m => configured.has(`${m.provider}/${m.id}`)),\n models: models.map(m => ({\n ref: `${m.provider}/${m.id}`,\n id: m.id,\n name: m.name,\n provider: m.provider,\n reasoning: m.reasoning ?? false,\n input: m.input ?? ['text'],\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n available: configured.has(`${m.provider}/${m.id}`),\n })),\n })),\n },\n });\n });\n\n // ========== Extension UI (manifest discovery + static assets) ==========\n\n authenticated.get('/api/extensions', async (c) => {\n const loader = service.getExtensionLoader();\n if (!loader) {\n return c.json({ extensions: [] });\n }\n\n const registry = loader.getRegistry();\n const discovered = loader.discoverExtensions();\n const activeIds = new Set<string>();\n for (const [id] of registry.extensions) {\n activeIds.add(id);\n }\n\n loader.setConfig(service.currentConfig as unknown as SurfaceConfig);\n let activationEligibleIds: Set<string> = new Set();\n try {\n const planner = new ActivationPlanner(loader.buildManifestRegistry());\n activationEligibleIds = new Set(\n planner.getActivatedIds(mergeActivationContext(service.currentConfig as unknown as SurfaceConfig)),\n );\n } catch {\n activationEligibleIds = new Set();\n }\n\n const extensions = discovered.map((ext) => ({\n id: ext.manifest.id,\n name: ext.manifest.name,\n description: ext.manifest.description,\n version: ext.manifest.version,\n kind: ext.manifest.kind,\n source: ext.source,\n active: activeIds.has(ext.id),\n activationEligible: activationEligibleIds.has(ext.id),\n hasUi: Boolean(ext.manifest.ui),\n ui: ext.manifest.ui\n ? {\n icon: ext.manifest.ui.icon,\n permissions: ext.manifest.ui.permissions,\n contributions: ext.manifest.ui.contributions,\n }\n : undefined,\n }));\n return c.json({ extensions });\n });\n\n /**\n * Built-in (bundled) extension enable/disable — persists `extensions.enabled` / `extensions.disabled`.\n * Body: `{ extensionId: string, enabled: boolean }`\n */\n authenticated.post('/api/extensions/bundled/activation', strictRateLimitMiddleware, async (c) => {\n const body = (await c.req.json().catch(() => null)) as\n | { extensionId?: unknown; enabled?: unknown }\n | null;\n const extensionId =\n typeof body?.extensionId === 'string' ? body.extensionId.trim() : '';\n if (!extensionId) {\n return c.json({ ok: false, error: { message: 'extensionId is required' } }, 400);\n }\n if (typeof body?.enabled !== 'boolean') {\n return c.json({ ok: false, error: { message: 'enabled must be a boolean' } }, 400);\n }\n const result = await service.setBundledExtensionActivationTarget(extensionId, body.enabled);\n if (!result.ok) {\n return c.json({ ok: false, error: { message: result.error ?? 'Request failed' } }, 400);\n }\n return c.json({\n ok: true,\n payload: { requiresGatewayRestart: result.requiresGatewayRestart },\n });\n });\n\n authenticated.get('/api/extensions/:id', async (c) => {\n const extensionId = c.req.param('id');\n const loader = service.getExtensionLoader();\n if (!loader) {\n return c.json({ error: 'Extensions unavailable' }, 503);\n }\n const discovered = loader.discoverExtensions();\n const ext = discovered.find((e) => e.id === extensionId);\n if (!ext) {\n return c.json({ error: 'Extension not found' }, 404);\n }\n const registry = loader.getRegistry();\n return c.json({\n id: ext.manifest.id,\n name: ext.manifest.name,\n description: ext.manifest.description,\n version: ext.manifest.version,\n kind: ext.manifest.kind,\n source: ext.source,\n path: ext.path,\n active: registry.extensions.has(ext.id),\n manifest: ext.manifest,\n });\n });\n\n authenticated.get('/api/extensions/:id/storage', async (c) => {\n const extensionId = c.req.param('id');\n const store = await loadExtensionStore(extensionId);\n return c.json({ keys: Object.keys(store) });\n });\n\n authenticated.get('/api/extensions/:id/storage/:key', async (c) => {\n const extensionId = c.req.param('id');\n const key = decodeURIComponent(c.req.param('key'));\n const store = await loadExtensionStore(extensionId);\n if (!(key in store)) {\n return c.json({ error: 'Key not found' }, 404);\n }\n return c.json({ value: store[key] });\n });\n\n authenticated.put('/api/extensions/:id/storage/:key', async (c) => {\n const extensionId = c.req.param('id');\n const key = decodeURIComponent(c.req.param('key'));\n const body = (await c.req.json().catch(() => null)) as { value?: unknown } | null;\n if (body === null || !('value' in body)) {\n return c.json({ error: 'Request body must contain a \"value\" field' }, 400);\n }\n const store = await loadExtensionStore(extensionId);\n store[key] = body.value;\n await saveExtensionStore(extensionId, store);\n return c.json({ ok: true });\n });\n\n authenticated.delete('/api/extensions/:id/storage/:key', async (c) => {\n const extensionId = c.req.param('id');\n const key = decodeURIComponent(c.req.param('key'));\n const store = await loadExtensionStore(extensionId);\n delete store[key];\n await saveExtensionStore(extensionId, store);\n return c.json({ ok: true });\n });\n\n authenticated.get('/api/extensions/:id/config', async (c) => {\n const extensionId = c.req.param('id');\n return c.json(await loadExtensionStore(`__config__${extensionId}`));\n });\n\n authenticated.patch('/api/extensions/:id/config', async (c) => {\n const extensionId = c.req.param('id');\n const patch = (await c.req.json().catch(() => null)) as Record<string, unknown> | null;\n if (!patch || typeof patch !== 'object' || Array.isArray(patch)) {\n return c.json({ error: 'Request body must be a JSON object' }, 400);\n }\n const namespace = `__config__${extensionId}`;\n const config = await loadExtensionStore(namespace);\n Object.assign(config, patch);\n await saveExtensionStore(namespace, config);\n return c.json({ ok: true });\n });\n\n // POST /api/registry/reload — reload gateway config and refresh model list for clients\n authenticated.post('/api/registry/reload', async (c) => {\n try {\n // Reload config\n await service.reloadConfig();\n \n // Reload OAuth credentials from new config\n loadOAuthCredentialsToCache(service);\n \n const models = getAllModels();\n \n // Emit SSE event to all connected clients\n service.emit('registry.updated', { modelCount: models.length });\n \n return c.json({\n ok: true,\n payload: {\n message: 'Registry reloaded',\n modelCount: models.length,\n },\n });\n } catch (err) {\n return c.json({\n error: err instanceof Error ? err.message : 'Failed to reload registry',\n }, 500);\n }\n });\n\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth-registry-extensions.js","names":["extensionMarketplace.searchExtensions","extensionMarketplace.listExtensions","extensionMarketplace.fetchRegistry"],"sources":["../../../../../src/gateway/hono/routes/auth-registry-extensions.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport { existsSync, readFileSync, statSync } from 'node:fs';\nimport { relative, resolve } from 'node:path';\n\nimport type { Config as SurfaceConfig } from '../../../config/config-surface.js';\nimport type { GatewayService } from '../../service.js';\nimport { buildWhenContextSnapshot } from '../../../extensions/when-context.js';\nimport * as extensionMarketplace from '../../../extensions/marketplace.js';\nimport { mergeActivationContext } from '../../../extensions/activation-context.js';\nimport { ActivationPlanner } from '../../../extensions/activation-planner.js';\nimport { getAllModels, getAvailableModels, type Model, type Api } from '../../../providers/index.js';\nimport { createOAuthHandler, loadOAuthCredentialsToCache } from '../oauth.js';\nimport { createOAuthAsyncHandler } from '../oauth-async.js';\nimport { extensionAssetMimeType } from '../lib/extension-assets.js';\nimport { loadExtensionStore, saveExtensionStore } from '../lib/extension-store.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst EXTENSION_ASSET_CSP =\n \"default-src 'self'; \" +\n \"script-src 'self' 'unsafe-inline'; \" +\n \"style-src 'self' 'unsafe-inline'; \" +\n \"img-src 'self' data: blob:; \" +\n \"connect-src 'none'; \" +\n \"frame-ancestors 'self'; \" +\n \"frame-src 'none'; \" +\n \"base-uri 'none'; \" +\n \"object-src 'none'; \" +\n \"form-action 'none'\";\n\nfunction rewriteExtensionAssetHtml(html: string, extensionId: string, assetPath: string): string {\n const assetDir = assetPath.includes('/') ? assetPath.slice(0, assetPath.lastIndexOf('/') + 1) : '';\n const assetBase = `/api/extensions/${extensionId}/assets/${assetDir}`;\n\n return html\n .replace(/(<script\\b[^>]*?\\ssrc=)([\"'])(\\.\\/)?([^\"']+)\\2/gi, (_match, tag, quote, _dot, file) => {\n const isAbsolute =\n file.startsWith('/') || file.startsWith('http://') || file.startsWith('https://');\n const resolvedSrc = isAbsolute ? file : `${assetBase}${file}`;\n return `${tag}${quote}${resolvedSrc}${quote} crossorigin=\"anonymous\"`;\n })\n .replace(/(<link\\b[^>]*?\\shref=)([\"'])(\\.\\/)?([^\"']+)\\2/gi, (_match, tag, quote, _dot, file) => {\n const isAbsolute =\n file.startsWith('/') || file.startsWith('http://') || file.startsWith('https://');\n const resolvedHref = isAbsolute ? file : `${assetBase}${file}`;\n return `${tag}${quote}${resolvedHref}${quote}`;\n });\n}\n\n/**\n * Register extension UI asset routes on the public (unauthenticated) app.\n *\n * Sandboxed iframes (`sandbox=\"allow-scripts …\"` without `allow-same-origin`) have an\n * opaque origin of `null`, so sub-resource requests from inside the iframe cannot\n * carry the `?token=` query parameter that was on the parent HTML URL. Putting these\n * routes behind the auth middleware therefore causes every JS/CSS asset to return 401.\n *\n * Security is maintained by the strict Content-Security-Policy returned with every\n * asset (`frame-ancestors 'self'`), which prevents any page other than the gateway\n * console itself from embedding the extension iframes.\n */\nexport function registerPublicExtensionAssetRoutes(app: Hono, service: GatewayService): void {\n app.get('/api/extensions/:id/assets/*', async (c) => {\n const extensionId = c.req.param('id');\n const loader = service.getExtensionLoader();\n if (!loader) {\n return c.json({ error: 'Extensions unavailable' }, 503);\n }\n\n const discovered = loader.discoverExtensions();\n const ext = discovered.find((e) => e.id === extensionId);\n if (!ext || !ext.manifest.ui) {\n return c.json({ error: 'Extension not found or has no UI' }, 404);\n }\n\n const prefix = `/api/extensions/${extensionId}/assets/`;\n const assetPathEncoded = c.req.path.startsWith(prefix) ? c.req.path.slice(prefix.length) : '';\n let assetPath = assetPathEncoded;\n try {\n assetPath = decodeURIComponent(assetPathEncoded);\n } catch {\n return c.json({ error: 'Invalid asset path' }, 400);\n }\n\n if (!assetPath || assetPath.includes('..')) {\n return c.json({ error: 'Invalid asset path' }, 400);\n }\n\n const root = resolve(ext.path);\n const fullPath = resolve(root, assetPath);\n const rel = relative(root, fullPath);\n if (rel.startsWith('..') || rel === '') {\n return c.json({ error: 'Path traversal denied' }, 403);\n }\n\n if (!existsSync(fullPath) || !statSync(fullPath).isFile()) {\n return c.json({ error: 'Not found' }, 404);\n }\n\n const rawContent = readFileSync(fullPath);\n const mimeType = extensionAssetMimeType(assetPath);\n\n const body: string | Uint8Array = mimeType.startsWith('text/html')\n ? rewriteExtensionAssetHtml(rawContent.toString('utf-8'), extensionId, assetPath)\n : new Uint8Array(rawContent);\n\n return new Response(body, {\n status: 200,\n headers: {\n 'Content-Type': mimeType,\n 'Content-Security-Policy': EXTENSION_ASSET_CSP,\n 'Cache-Control': 'no-store',\n 'X-Content-Type-Options': 'nosniff',\n 'Access-Control-Allow-Origin': 'null',\n },\n });\n });\n}\n\nexport function registerAuthRegistryExtensionsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n // ========== Auth API (/api/auth) ==========\n\n // GET /api/auth/token - Get current gateway token\n authenticated.get('/api/auth/token', (c) => {\n const authToken = service.getAuthToken();\n return c.json({ \n ok: true, \n payload: { \n token: authToken,\n mode: service.getAuthMode(),\n } \n });\n });\n\n // POST /api/auth/token/refresh - Generate new gateway token\n authenticated.post('/api/auth/token/refresh', async (c) => {\n try {\n const newToken = await service.refreshAuthToken();\n return c.json({ \n ok: true, \n payload: { \n token: newToken,\n message: 'Token refreshed successfully. Please update your client configuration.'\n } \n });\n } catch (err) {\n return c.json({ \n ok: false, \n error: err instanceof Error ? err.message : 'Failed to refresh token' \n }, 500);\n }\n });\n\n // ========== OAuth API (/api/auth/oauth) ==========\n authenticated.route('/api/auth/oauth', createOAuthHandler(service));\n\n // ========== Async OAuth API (/api/auth/oauth-async) ==========\n authenticated.route('/api/auth/oauth-async', createOAuthAsyncHandler(service));\n\n // Load OAuth credentials from config into cache on startup\n loadOAuthCredentialsToCache(service);\n\n // ========== Registry API ==========\n \n // GET /api/registry - Full registry for frontend\n authenticated.get('/api/registry', async (c) => {\n const allModels = getAllModels();\n const availableModels = await getAvailableModels();\n const configured = new Set(availableModels.map(m => `${m.provider}/${m.id}`));\n \n // Group models by provider\n const providerMap = new Map<string, Model<Api>[]>();\n for (const model of allModels) {\n const list = providerMap.get(model.provider) ?? [];\n list.push(model);\n providerMap.set(model.provider, list);\n }\n \n return c.json({\n ok: true,\n payload: {\n version: 'pi-ai',\n providers: Array.from(providerMap.entries()).map(([id, models]) => ({\n id,\n name: id.charAt(0).toUpperCase() + id.slice(1),\n configured: models.some(m => configured.has(`${m.provider}/${m.id}`)),\n models: models.map(m => ({\n ref: `${m.provider}/${m.id}`,\n id: m.id,\n name: m.name,\n provider: m.provider,\n reasoning: m.reasoning ?? false,\n input: m.input ?? ['text'],\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n available: configured.has(`${m.provider}/${m.id}`),\n })),\n })),\n },\n });\n });\n\n // ========== Extension UI (manifest discovery + static assets) ==========\n\n authenticated.get('/api/extensions', async (c) => {\n const loader = service.getExtensionLoader();\n if (!loader) {\n return c.json({ extensions: [] });\n }\n\n const registry = loader.getRegistry();\n const discovered = loader.discoverExtensions();\n const activeIds = new Set<string>();\n for (const [id] of registry.extensions) {\n activeIds.add(id);\n }\n\n loader.setConfig(service.currentConfig as unknown as SurfaceConfig);\n let activationEligibleIds: Set<string> = new Set();\n try {\n const planner = new ActivationPlanner(loader.buildManifestRegistry());\n activationEligibleIds = new Set(\n planner.getActivatedIds(mergeActivationContext(service.currentConfig as unknown as SurfaceConfig)),\n );\n } catch {\n activationEligibleIds = new Set();\n }\n\n const extensions = discovered.map((ext) => ({\n id: ext.manifest.id,\n name: ext.manifest.name,\n description: ext.manifest.description,\n version: ext.manifest.version,\n kind: ext.manifest.kind,\n source: ext.source,\n active: activeIds.has(ext.id),\n activationEligible: activationEligibleIds.has(ext.id),\n hasUi: Boolean(ext.manifest.ui),\n hasConfigSchema: Boolean(ext.manifest.configSchema),\n ui: ext.manifest.ui\n ? {\n icon: ext.manifest.ui.icon,\n permissions: ext.manifest.ui.permissions,\n contributions: ext.manifest.ui.contributions,\n }\n : undefined,\n }));\n return c.json({ extensions });\n });\n\n /**\n * Built-in (bundled) extension enable/disable — persists `extensions.enabled` / `extensions.disabled`.\n * Body: `{ extensionId: string, enabled: boolean }`\n */\n authenticated.post('/api/extensions/bundled/activation', strictRateLimitMiddleware, async (c) => {\n const body = (await c.req.json().catch(() => null)) as\n | { extensionId?: unknown; enabled?: unknown }\n | null;\n const extensionId =\n typeof body?.extensionId === 'string' ? body.extensionId.trim() : '';\n if (!extensionId) {\n return c.json({ ok: false, error: { message: 'extensionId is required' } }, 400);\n }\n if (typeof body?.enabled !== 'boolean') {\n return c.json({ ok: false, error: { message: 'enabled must be a boolean' } }, 400);\n }\n const result = await service.setBundledExtensionActivationTarget(extensionId, body.enabled);\n if (!result.ok) {\n return c.json({ ok: false, error: { message: result.error ?? 'Request failed' } }, 400);\n }\n return c.json({\n ok: true,\n payload: { requiresGatewayRestart: result.requiresGatewayRestart },\n });\n });\n\n authenticated.get('/api/extensions/:id', async (c) => {\n const extensionId = c.req.param('id');\n const loader = service.getExtensionLoader();\n if (!loader) {\n return c.json({ error: 'Extensions unavailable' }, 503);\n }\n const discovered = loader.discoverExtensions();\n const ext = discovered.find((e) => e.id === extensionId);\n if (!ext) {\n return c.json({ error: 'Extension not found' }, 404);\n }\n const registry = loader.getRegistry();\n return c.json({\n id: ext.manifest.id,\n name: ext.manifest.name,\n description: ext.manifest.description,\n version: ext.manifest.version,\n kind: ext.manifest.kind,\n source: ext.source,\n path: ext.path,\n active: registry.extensions.has(ext.id),\n manifest: ext.manifest,\n });\n });\n\n authenticated.get('/api/extensions/:id/storage', async (c) => {\n const extensionId = c.req.param('id');\n const store = await loadExtensionStore(extensionId);\n return c.json({ keys: Object.keys(store) });\n });\n\n authenticated.get('/api/extensions/:id/storage/:key', async (c) => {\n const extensionId = c.req.param('id');\n const key = decodeURIComponent(c.req.param('key'));\n const store = await loadExtensionStore(extensionId);\n if (!(key in store)) {\n return c.json({ error: 'Key not found' }, 404);\n }\n return c.json({ value: store[key] });\n });\n\n authenticated.put('/api/extensions/:id/storage/:key', async (c) => {\n const extensionId = c.req.param('id');\n const key = decodeURIComponent(c.req.param('key'));\n const body = (await c.req.json().catch(() => null)) as { value?: unknown } | null;\n if (body === null || !('value' in body)) {\n return c.json({ error: 'Request body must contain a \"value\" field' }, 400);\n }\n const store = await loadExtensionStore(extensionId);\n store[key] = body.value;\n await saveExtensionStore(extensionId, store);\n return c.json({ ok: true });\n });\n\n authenticated.delete('/api/extensions/:id/storage/:key', async (c) => {\n const extensionId = c.req.param('id');\n const key = decodeURIComponent(c.req.param('key'));\n const store = await loadExtensionStore(extensionId);\n delete store[key];\n await saveExtensionStore(extensionId, store);\n return c.json({ ok: true });\n });\n\n authenticated.get('/api/extensions/:id/config', async (c) => {\n const extensionId = c.req.param('id');\n return c.json(await loadExtensionStore(`__config__${extensionId}`));\n });\n\n authenticated.patch('/api/extensions/:id/config', async (c) => {\n const extensionId = c.req.param('id');\n const patch = (await c.req.json().catch(() => null)) as Record<string, unknown> | null;\n if (!patch || typeof patch !== 'object' || Array.isArray(patch)) {\n return c.json({ error: 'Request body must be a JSON object' }, 400);\n }\n const namespace = `__config__${extensionId}`;\n const config = await loadExtensionStore(namespace);\n Object.assign(config, patch);\n await saveExtensionStore(namespace, config);\n return c.json({ ok: true });\n });\n\n authenticated.get('/api/context', (c) => {\n const loader = service.getExtensionLoader();\n const snapshot = buildWhenContextSnapshot(\n service.currentConfig as unknown as SurfaceConfig,\n loader,\n );\n return c.json(snapshot);\n });\n\n authenticated.get('/api/marketplace', async (c) => {\n const q = c.req.query('q');\n const category = c.req.query('category');\n try {\n let extensions;\n if (typeof q === 'string' && q.trim()) {\n extensions = await extensionMarketplace.searchExtensions(q.trim());\n } else if (typeof category === 'string' && category.trim()) {\n extensions = await extensionMarketplace.listExtensions(category.trim());\n } else {\n const reg = await extensionMarketplace.fetchRegistry();\n extensions = reg.extensions;\n }\n return c.json({ ok: true, extensions });\n } catch (err) {\n return c.json(\n {\n ok: false,\n extensions: [],\n error: err instanceof Error ? err.message : 'marketplace fetch failed',\n },\n 500,\n );\n }\n });\n\n // POST /api/registry/reload — reload gateway config and refresh model list for clients\n authenticated.post('/api/registry/reload', async (c) => {\n try {\n // Reload config\n await service.reloadConfig();\n \n // Reload OAuth credentials from new config\n loadOAuthCredentialsToCache(service);\n \n const models = getAllModels();\n \n // Emit SSE event to all connected clients\n service.emit('registry.updated', { modelCount: models.length });\n \n return c.json({\n ok: true,\n payload: {\n message: 'Registry reloaded',\n modelCount: models.length,\n },\n });\n } catch (err) {\n return c.json({\n error: err instanceof Error ? err.message : 'Failed to reload registry',\n }, 500);\n }\n });\n\n}\n"],"mappings":"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"}
|
|
@@ -52,14 +52,17 @@ export declare function providerSupportsApiKey(provider: string): boolean;
|
|
|
52
52
|
/**
|
|
53
53
|
* Get a default model reference.
|
|
54
54
|
* Priority:
|
|
55
|
-
* 1.
|
|
56
|
-
* 2.
|
|
57
|
-
* 3. Fallback to anthropic/claude-sonnet-4-5 as last resort
|
|
55
|
+
* 1. Explicitly configured model in agents.defaults.model (if set and available)
|
|
56
|
+
* 2. Default fallback: deepseek/deepseek-v4-flash
|
|
58
57
|
*/
|
|
59
58
|
export declare function getDefaultModel(config?: Config | null | undefined): Promise<string>;
|
|
60
59
|
/**
|
|
61
60
|
* Synchronous default model resolution for constructors and sync code paths.
|
|
62
61
|
* Uses catalog/registry only (no async credential checks).
|
|
62
|
+
*
|
|
63
|
+
* When no model is explicitly configured, returns the preferred default
|
|
64
|
+
* (`deepseek/deepseek-v4-flash`) rather than picking an arbitrary first
|
|
65
|
+
* model from the full catalog.
|
|
63
66
|
*/
|
|
64
67
|
export declare function getDefaultModelSync(config?: Config | null | undefined): string;
|
|
65
68
|
export { ModelRegistry, getModelRegistry, resetModelRegistry } from './model-registry.js';
|
|
@@ -207,32 +207,28 @@ function providerSupportsApiKey(provider) {
|
|
|
207
207
|
/**
|
|
208
208
|
* Get a default model reference.
|
|
209
209
|
* Priority:
|
|
210
|
-
* 1.
|
|
211
|
-
* 2.
|
|
212
|
-
* 3. Fallback to anthropic/claude-sonnet-4-5 as last resort
|
|
210
|
+
* 1. Explicitly configured model in agents.defaults.model (if set and available)
|
|
211
|
+
* 2. Default fallback: deepseek/deepseek-v4-flash
|
|
213
212
|
*/
|
|
214
213
|
async function getDefaultModel(config) {
|
|
215
|
-
const availableModels = await getAvailableModels();
|
|
216
214
|
const defaultModel = config?.agents?.defaults?.model;
|
|
217
215
|
if (defaultModel) {
|
|
218
216
|
const modelRef = typeof defaultModel === "string" ? defaultModel : defaultModel.primary;
|
|
219
217
|
if (modelRef) {
|
|
220
|
-
const configured =
|
|
218
|
+
const configured = (await getAvailableModels()).find((m) => `${m.provider}/${m.id}` === modelRef || m.id === modelRef);
|
|
221
219
|
if (configured) return `${configured.provider}/${configured.id}`;
|
|
220
|
+
return modelRef;
|
|
222
221
|
}
|
|
223
222
|
}
|
|
224
|
-
|
|
225
|
-
for (const provider of getProviders()) try {
|
|
226
|
-
const models = getModels(provider);
|
|
227
|
-
if (models.length > 0) return `${provider}/${models[0].id}`;
|
|
228
|
-
} catch {
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
return "anthropic/claude-sonnet-4-5";
|
|
223
|
+
return DEFAULT_FALLBACK_MODEL;
|
|
232
224
|
}
|
|
233
225
|
/**
|
|
234
226
|
* Synchronous default model resolution for constructors and sync code paths.
|
|
235
227
|
* Uses catalog/registry only (no async credential checks).
|
|
228
|
+
*
|
|
229
|
+
* When no model is explicitly configured, returns the preferred default
|
|
230
|
+
* (`deepseek/deepseek-v4-flash`) rather than picking an arbitrary first
|
|
231
|
+
* model from the full catalog.
|
|
236
232
|
*/
|
|
237
233
|
function getDefaultModelSync(config) {
|
|
238
234
|
const defaultModel = config?.agents?.defaults?.model;
|
|
@@ -240,17 +236,9 @@ function getDefaultModelSync(config) {
|
|
|
240
236
|
const modelRef = typeof defaultModel === "string" ? defaultModel : defaultModel.primary;
|
|
241
237
|
if (modelRef) return modelRef;
|
|
242
238
|
}
|
|
243
|
-
|
|
244
|
-
if (all.length > 0) return `${all[0].provider}/${all[0].id}`;
|
|
245
|
-
for (const provider of getProviders()) try {
|
|
246
|
-
const models = getModels(provider);
|
|
247
|
-
if (models.length > 0) return `${provider}/${models[0].id}`;
|
|
248
|
-
} catch {
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
return "anthropic/claude-sonnet-4-5";
|
|
239
|
+
return DEFAULT_FALLBACK_MODEL;
|
|
252
240
|
}
|
|
253
|
-
var EXTENSION_PROVIDER_BASE_URL, PROVIDER_META;
|
|
241
|
+
var EXTENSION_PROVIDER_BASE_URL, PROVIDER_META, DEFAULT_FALLBACK_MODEL;
|
|
254
242
|
var init_providers = __esmMin((() => {
|
|
255
243
|
init_model_registry();
|
|
256
244
|
init_credentials();
|
|
@@ -391,6 +379,7 @@ var init_providers = __esmMin((() => {
|
|
|
391
379
|
supportsOAuth: true
|
|
392
380
|
}
|
|
393
381
|
};
|
|
382
|
+
DEFAULT_FALLBACK_MODEL = "deepseek/deepseek-v4-flash";
|
|
394
383
|
}));
|
|
395
384
|
//#endregion
|
|
396
385
|
init_providers();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["getPiAiModel","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/index.ts"],"sourcesContent":["/**\n * Model provider module - integrates built-in models with custom models from models.json\n */\n\nimport {\n\tgetModel as getPiAiModel,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype Api,\n} from '@mariozechner/pi-ai';\nimport type { Config } from '../config/schema.js';\nimport { getModelRegistry } from './model-registry.js';\nimport { CredentialResolver, resolveApiKey, hasCredentials } from '../auth/credentials.js';\nimport { hasProviderAuthOnDiskSync } from '../auth/sync-provider-auth.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\nimport { getProviderRegistry } from './plugin-registry.js';\nimport type { ProviderModelDefinition } from '../extensions/types/providers.js';\n\nexport { getApiKeyFromEnv, PROVIDER_ENV_MAP } from './env-keys.js';\n\n/** Sentinel base URL: model is served by an extension {@link ProviderPluginRegistry} provider. */\nexport const EXTENSION_PROVIDER_BASE_URL = 'extension://provider-plugin';\n\n/** Map a plugin registry model to the pi-ai {@link Model} shape. */\nexport function pluginModelToModel(providerId: string, definition: ProviderModelDefinition): Model<Api> {\n\treturn {\n\t\tprovider: providerId,\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tapi: 'openai-completions' as Api,\n\t\tbaseUrl: EXTENSION_PROVIDER_BASE_URL,\n\t\treasoning: false,\n\t\tinput: definition.supportsImages ? (['text', 'image'] as ('text' | 'image')[]) : (['text'] as ('text' | 'image')[]),\n\t\tcontextWindow: definition.contextWindow ?? 128000,\n\t\tmaxTokens: definition.maxOutputTokens ?? 4096,\n\t\tcost: {\n\t\t\tinput: definition.pricing?.input ?? 0,\n\t\t\toutput: definition.pricing?.output ?? 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t},\n\t} as Model<Api>;\n}\n\n/**\n * Get API key synchronously: checks registry (models.json) first, then environment variables.\n * Use this for Agent's getApiKey callback which must be synchronous.\n */\nexport function getApiKeySync(provider: string): string | undefined {\n const pluginRegistry = getProviderRegistry();\n if (pluginRegistry.has(provider)) return 'extension-managed';\n\n const registry = getModelRegistry();\n const registryKey = registry.getApiKey(provider);\n if (registryKey) {\n return registryKey;\n }\n return getApiKeyFromEnv(provider);\n}\n\n/**\n * Resolve model reference. Supports:\n * - \"provider/modelId\" format\n * - \"modelId\" auto-detection via pi-ai or custom models\n * @throws if model not found\n */\nexport function resolveModel(ref: string): Model<Api> {\n\t// First try ModelRegistry (includes custom models)\n\tconst registry = getModelRegistry();\n\tconst customModel = registry.resolve(ref);\n\tif (customModel) {\n\t\treturn customModel;\n\t}\n\n\tif (ref.includes('/')) {\n\t\tconst [provider, modelId] = ref.split('/');\n\t\tconst piAiModel = getPiAiModel(provider as any, modelId as any);\n\t\tif (piAiModel) return piAiModel as Model<Api>;\n\n\t\tconst pluginRegistry = getProviderRegistry();\n\t\tconst plugin = pluginRegistry.get(provider);\n\t\tif (plugin) {\n\t\t\tconst pluginModel = plugin.models.find(m => m.id === modelId);\n\t\t\tif (pluginModel) return pluginModelToModel(provider, pluginModel);\n\t\t}\n\t\tthrow new Error(`Model not found: ${ref}`);\n\t}\n\n\tfor (const provider of getPiAiProviders()) {\n\t\ttry {\n\t\t\tconst models = getPiAiModels(provider);\n\t\t\tconst found = models.find(m => m.id === ref);\n\t\t\tif (found) return found as Model<Api>;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tconst pluginRegistry = getProviderRegistry();\n\tfor (const plugin of pluginRegistry.listAll()) {\n\t\tconst found = plugin.models.find(m => m.id === ref);\n\t\tif (found) return pluginModelToModel(plugin.id, found);\n\t}\n\n\tthrow new Error(`Model not found: ${ref}. Use format: provider/model-id`);\n}\n\nexport function getModelsByProvider(provider: string): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst fromRegistry = registry.getAll().filter(m => m.provider === provider);\n\tconst plugin = getProviderRegistry().get(provider);\n\tif (!plugin) return fromRegistry;\n\tconst pluginModels = plugin.models.map(m => pluginModelToModel(provider, m));\n\treturn [...fromRegistry, ...pluginModels];\n}\n\nexport function getAllProviders(): string[] {\n\tconst registry = getModelRegistry();\n\tconst providers = new Set<string>();\n\n\t// Add built-in providers\n\tfor (const p of getPiAiProviders()) {\n\t\tproviders.add(p);\n\t}\n\n\t// Add custom providers from registry\n\tfor (const m of registry.getAll()) {\n\t\tproviders.add(m.provider);\n\t}\n\n\tfor (const plugin of getProviderRegistry().listAll()) {\n\t\tproviders.add(plugin.id);\n\t}\n\n\treturn Array.from(providers);\n}\n\nexport async function getApiKey(provider: string): Promise<string | undefined> {\n\tif (getProviderRegistry().has(provider)) return 'extension-managed';\n\n\t// Use new credential resolver first (checks: agent private > global > oauth > env)\n\tconst credentialKey = await resolveApiKey(provider);\n\tif (credentialKey) {\n\t\treturn credentialKey;\n\t}\n\n\t// Check registry for custom providers (from models.json)\n\tconst registry = getModelRegistry();\n\tconst registryKey = registry.getApiKey(provider);\n\tif (registryKey) {\n\t\treturn registryKey;\n\t}\n\n\t// Fallback to environment variables\n\treturn getApiKeyFromEnv(provider);\n}\n\n/**\n * Synchronous version for use in non-async contexts\n * Only checks environment variables and registry, not credential system\n */\nexport function isProviderConfiguredSync(provider: string): boolean {\n\tif (getProviderRegistry().has(provider)) return true;\n\n\t// Check registry for custom providers\n\tconst registry = getModelRegistry();\n\tif (registry.getApiKey(provider)) {\n\t\treturn true;\n\t}\n\t// Check environment variables\n\tif (getApiKeyFromEnv(provider)) {\n\t\treturn true;\n\t}\n\t// Gateway UI / CLI store keys in auth-profiles.json (async CredentialResolver); sync path for fallback list\n\treturn hasProviderAuthOnDiskSync(provider);\n}\n\nexport async function isProviderConfigured(provider: string): Promise<boolean> {\n if (getProviderRegistry().has(provider)) return true;\n\n // Check registry first for custom providers (from models.json)\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return true;\n }\n return await hasCredentials(provider);\n}\n\n/** Where runtime {@link getApiKey} resolves the key from (no secret values). */\nexport type ProviderActiveKeySource = 'none' | 'agent' | 'gateway' | 'oauth' | 'env' | 'models_json' | 'extension';\n\nexport async function getProviderActiveKeySource(provider: string): Promise<ProviderActiveKeySource> {\n if (getProviderRegistry().has(provider)) return 'extension';\n\n const resolver = new CredentialResolver();\n const fromCredentials = await resolver.resolveApiKeySource(provider);\n if (fromCredentials === 'agent') return 'agent';\n if (fromCredentials === 'global') return 'gateway';\n if (fromCredentials === 'oauth') return 'oauth';\n if (fromCredentials === 'env') return 'env';\n\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return 'models_json';\n }\n\n return 'none';\n}\n\nexport async function getConfiguredProviders(): Promise<string[]> {\n\tconst allProviders = getAllProviders();\n\tconst configured: string[] = [];\n\tfor (const p of allProviders) {\n\t\tif (await isProviderConfigured(p)) {\n\t\t\tconfigured.push(p);\n\t\t}\n\t}\n\treturn configured;\n}\n\nexport function getAllModels(): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst registryModels = registry.getAll();\n\tconst pluginProviders = getProviderRegistry().listAll();\n\tif (pluginProviders.length === 0) return registryModels;\n\n\tconst existingIds = new Set(registryModels.map(m => `${m.provider}/${m.id}`));\n\tconst merged: Model<Api>[] = [...registryModels];\n\tfor (const plugin of pluginProviders) {\n\t\tfor (const model of plugin.models) {\n\t\t\tconst compositeId = `${plugin.id}/${model.id}`;\n\t\t\tif (!existingIds.has(compositeId)) {\n\t\t\t\tmerged.push(pluginModelToModel(plugin.id, model));\n\t\t\t\texistingIds.add(compositeId);\n\t\t\t}\n\t\t}\n\t}\n\treturn merged;\n}\n\nexport async function getAvailableModels(): Promise<readonly Model<Api>[]> {\n\tconst allModels = getAllModels();\n\tconst pluginRegistry = getProviderRegistry();\n\tconst available: Model<Api>[] = [];\n\n\tfor (const model of allModels) {\n\t\tif (pluginRegistry.has(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t} else if (await isProviderConfigured(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t}\n\t}\n\treturn available;\n}\n\nexport type { Model, Api } from '@mariozechner/pi-ai';\n\nexport type ProviderCategory = 'common' | 'specialty' | 'oauth' | 'enterprise' | 'extension';\n\nexport interface ProviderMeta {\n name: string;\n category: ProviderCategory;\n supportsOAuth?: boolean;\n supportsApiKey?: boolean;\n}\n\nexport const PROVIDER_META: Record<string, ProviderMeta> = {\n 'openai': { name: 'OpenAI (GPT-4, o1, o3)', category: 'common', supportsApiKey: true },\n 'anthropic': { name: 'Anthropic Claude', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'deepseek': { name: 'DeepSeek', category: 'common', supportsApiKey: true },\n 'google': { name: 'Google Gemini', category: 'common', supportsApiKey: true },\n 'groq': { name: 'Groq (Fast Inference)', category: 'common', supportsApiKey: true },\n 'minimax': { name: 'MiniMax', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'minimax-cn': { name: 'MiniMax CN', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'kimi-coding': { name: 'Kimi For Coding', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'xai': { name: 'xAI (Grok)', category: 'specialty', supportsApiKey: true },\n 'mistral': { name: 'Mistral AI', category: 'specialty', supportsApiKey: true },\n 'cerebras': { name: 'Cerebras', category: 'specialty', supportsApiKey: true },\n 'openrouter': { name: 'OpenRouter (Multi-provider)', category: 'specialty', supportsApiKey: true },\n 'huggingface': { name: 'Hugging Face', category: 'specialty', supportsApiKey: true },\n 'opencode': { name: 'OpenCode', category: 'specialty', supportsApiKey: true },\n 'opencode-go': { name: 'OpenCode Go', category: 'specialty', supportsApiKey: true },\n /** DashScope (Alibaba) — image, speech, STT; not an LLM KnownProvider. */\n 'dashscope': { name: 'DashScope (Alibaba)', category: 'specialty', supportsApiKey: true },\n /** International GLM (api.z.ai). Auth: API key (ZAI_API_KEY); no published OAuth for this HTTP API. */\n 'zai': { name: 'Zhipu GLM (International · z.ai)', category: 'common', supportsApiKey: true },\n 'amazon-bedrock': { name: 'Amazon Bedrock', category: 'enterprise', supportsApiKey: true },\n 'azure-openai-responses': { name: 'Azure OpenAI', category: 'enterprise', supportsApiKey: true },\n 'google-vertex': { name: 'Google Vertex AI', category: 'enterprise', supportsApiKey: true },\n 'vercel-ai-gateway': { name: 'Vercel AI Gateway', category: 'enterprise', supportsApiKey: true },\n 'github-copilot': { name: 'GitHub Copilot (OAuth)', category: 'oauth', supportsOAuth: true },\n 'openai-codex': { name: 'OpenAI Codex (OAuth)', category: 'oauth', supportsOAuth: true },\n 'google-gemini-cli': { name: 'Google Gemini CLI (OAuth)', category: 'oauth', supportsOAuth: true },\n 'google-antigravity': { name: 'Google Antigravity (OAuth)', category: 'oauth', supportsOAuth: true },\n};\n\nexport function getSortedProviders(): string[] {\n const all = getAllProviders();\n const catOrder: Record<ProviderCategory, number> = { common: 0, specialty: 1, enterprise: 2, oauth: 3, extension: 4 };\n const pluginRegistry = getProviderRegistry();\n\n return [...all].sort((a, b) => {\n const catA = pluginRegistry.has(a) ? 'extension' : (PROVIDER_META[a]?.category ?? 'specialty');\n const catB = pluginRegistry.has(b) ? 'extension' : (PROVIDER_META[b]?.category ?? 'specialty');\n if (catOrder[catA] !== catOrder[catB]) {\n return catOrder[catA] - catOrder[catB];\n }\n return a.localeCompare(b);\n });\n}\n\nexport function getProviderDisplayName(provider: string): string {\n const plugin = getProviderRegistry().get(provider);\n if (plugin) return plugin.name;\n return PROVIDER_META[provider]?.name || provider;\n}\n\nexport function providerSupportsOAuth(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsOAuth ?? false;\n}\n\nexport function providerSupportsApiKey(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsApiKey ?? true;\n}\n\n// ============================================\n// Dynamic Default Model Resolution\n// ============================================\n\n/**\n * Get a default model reference.\n * Priority:\n * 1. First available model with configured API key\n * 2. First model from pi-ai catalog\n * 3. Fallback to anthropic/claude-sonnet-4-5 as last resort\n */\nexport async function getDefaultModel(config?: Config | null | undefined): Promise<string> {\n const availableModels = await getAvailableModels();\n \n // Try to find configured default model first\n const defaultModel = config?.agents?.defaults?.model;\n if (defaultModel) {\n const modelRef = typeof defaultModel === 'string' ? defaultModel : defaultModel.primary;\n if (modelRef) {\n // Check if the configured model has valid API key\n const configured = availableModels.find(m => \n `${m.provider}/${m.id}` === modelRef ||\n m.id === modelRef\n );\n if (configured) {\n return `${configured.provider}/${configured.id}`;\n }\n }\n }\n \n // Return first available model\n if (availableModels.length > 0) {\n return `${availableModels[0].provider}/${availableModels[0].id}`;\n }\n \n // Try to get first model from pi-ai catalog\n for (const provider of getPiAiProviders()) {\n try {\n const models = getPiAiModels(provider);\n if (models.length > 0) {\n return `${provider}/${models[0].id}`;\n }\n } catch {\n continue;\n }\n }\n \n // Last resort fallback\n return 'anthropic/claude-sonnet-4-5';\n}\n\n/**\n * Synchronous default model resolution for constructors and sync code paths.\n * Uses catalog/registry only (no async credential checks).\n */\nexport function getDefaultModelSync(config?: Config | null | undefined): string {\n const defaultModel = config?.agents?.defaults?.model;\n if (defaultModel) {\n const modelRef = typeof defaultModel === 'string' ? defaultModel : defaultModel.primary;\n if (modelRef) {\n return modelRef;\n }\n }\n const all = getAllModels();\n if (all.length > 0) {\n return `${all[0].provider}/${all[0].id}`;\n }\n for (const provider of getPiAiProviders()) {\n try {\n const models = getPiAiModels(provider);\n if (models.length > 0) {\n return `${provider}/${models[0].id}`;\n }\n } catch {\n continue;\n }\n }\n return 'anthropic/claude-sonnet-4-5';\n}\n\n// Re-export ModelRegistry for advanced use cases\nexport { ModelRegistry, getModelRegistry, resetModelRegistry } from './model-registry.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["getPiAiModel","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/index.ts"],"sourcesContent":["/**\n * Model provider module - integrates built-in models with custom models from models.json\n */\n\nimport {\n\tgetModel as getPiAiModel,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype Api,\n} from '@mariozechner/pi-ai';\nimport type { Config } from '../config/schema.js';\nimport { getModelRegistry } from './model-registry.js';\nimport { CredentialResolver, resolveApiKey, hasCredentials } from '../auth/credentials.js';\nimport { hasProviderAuthOnDiskSync } from '../auth/sync-provider-auth.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\nimport { getProviderRegistry } from './plugin-registry.js';\nimport type { ProviderModelDefinition } from '../extensions/types/providers.js';\n\nexport { getApiKeyFromEnv, PROVIDER_ENV_MAP } from './env-keys.js';\n\n/** Sentinel base URL: model is served by an extension {@link ProviderPluginRegistry} provider. */\nexport const EXTENSION_PROVIDER_BASE_URL = 'extension://provider-plugin';\n\n/** Map a plugin registry model to the pi-ai {@link Model} shape. */\nexport function pluginModelToModel(providerId: string, definition: ProviderModelDefinition): Model<Api> {\n\treturn {\n\t\tprovider: providerId,\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tapi: 'openai-completions' as Api,\n\t\tbaseUrl: EXTENSION_PROVIDER_BASE_URL,\n\t\treasoning: false,\n\t\tinput: definition.supportsImages ? (['text', 'image'] as ('text' | 'image')[]) : (['text'] as ('text' | 'image')[]),\n\t\tcontextWindow: definition.contextWindow ?? 128000,\n\t\tmaxTokens: definition.maxOutputTokens ?? 4096,\n\t\tcost: {\n\t\t\tinput: definition.pricing?.input ?? 0,\n\t\t\toutput: definition.pricing?.output ?? 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t},\n\t} as Model<Api>;\n}\n\n/**\n * Get API key synchronously: checks registry (models.json) first, then environment variables.\n * Use this for Agent's getApiKey callback which must be synchronous.\n */\nexport function getApiKeySync(provider: string): string | undefined {\n const pluginRegistry = getProviderRegistry();\n if (pluginRegistry.has(provider)) return 'extension-managed';\n\n const registry = getModelRegistry();\n const registryKey = registry.getApiKey(provider);\n if (registryKey) {\n return registryKey;\n }\n return getApiKeyFromEnv(provider);\n}\n\n/**\n * Resolve model reference. Supports:\n * - \"provider/modelId\" format\n * - \"modelId\" auto-detection via pi-ai or custom models\n * @throws if model not found\n */\nexport function resolveModel(ref: string): Model<Api> {\n\t// First try ModelRegistry (includes custom models)\n\tconst registry = getModelRegistry();\n\tconst customModel = registry.resolve(ref);\n\tif (customModel) {\n\t\treturn customModel;\n\t}\n\n\tif (ref.includes('/')) {\n\t\tconst [provider, modelId] = ref.split('/');\n\t\tconst piAiModel = getPiAiModel(provider as any, modelId as any);\n\t\tif (piAiModel) return piAiModel as Model<Api>;\n\n\t\tconst pluginRegistry = getProviderRegistry();\n\t\tconst plugin = pluginRegistry.get(provider);\n\t\tif (plugin) {\n\t\t\tconst pluginModel = plugin.models.find(m => m.id === modelId);\n\t\t\tif (pluginModel) return pluginModelToModel(provider, pluginModel);\n\t\t}\n\t\tthrow new Error(`Model not found: ${ref}`);\n\t}\n\n\tfor (const provider of getPiAiProviders()) {\n\t\ttry {\n\t\t\tconst models = getPiAiModels(provider);\n\t\t\tconst found = models.find(m => m.id === ref);\n\t\t\tif (found) return found as Model<Api>;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tconst pluginRegistry = getProviderRegistry();\n\tfor (const plugin of pluginRegistry.listAll()) {\n\t\tconst found = plugin.models.find(m => m.id === ref);\n\t\tif (found) return pluginModelToModel(plugin.id, found);\n\t}\n\n\tthrow new Error(`Model not found: ${ref}. Use format: provider/model-id`);\n}\n\nexport function getModelsByProvider(provider: string): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst fromRegistry = registry.getAll().filter(m => m.provider === provider);\n\tconst plugin = getProviderRegistry().get(provider);\n\tif (!plugin) return fromRegistry;\n\tconst pluginModels = plugin.models.map(m => pluginModelToModel(provider, m));\n\treturn [...fromRegistry, ...pluginModels];\n}\n\nexport function getAllProviders(): string[] {\n\tconst registry = getModelRegistry();\n\tconst providers = new Set<string>();\n\n\t// Add built-in providers\n\tfor (const p of getPiAiProviders()) {\n\t\tproviders.add(p);\n\t}\n\n\t// Add custom providers from registry\n\tfor (const m of registry.getAll()) {\n\t\tproviders.add(m.provider);\n\t}\n\n\tfor (const plugin of getProviderRegistry().listAll()) {\n\t\tproviders.add(plugin.id);\n\t}\n\n\treturn Array.from(providers);\n}\n\nexport async function getApiKey(provider: string): Promise<string | undefined> {\n\tif (getProviderRegistry().has(provider)) return 'extension-managed';\n\n\t// Use new credential resolver first (checks: agent private > global > oauth > env)\n\tconst credentialKey = await resolveApiKey(provider);\n\tif (credentialKey) {\n\t\treturn credentialKey;\n\t}\n\n\t// Check registry for custom providers (from models.json)\n\tconst registry = getModelRegistry();\n\tconst registryKey = registry.getApiKey(provider);\n\tif (registryKey) {\n\t\treturn registryKey;\n\t}\n\n\t// Fallback to environment variables\n\treturn getApiKeyFromEnv(provider);\n}\n\n/**\n * Synchronous version for use in non-async contexts\n * Only checks environment variables and registry, not credential system\n */\nexport function isProviderConfiguredSync(provider: string): boolean {\n\tif (getProviderRegistry().has(provider)) return true;\n\n\t// Check registry for custom providers\n\tconst registry = getModelRegistry();\n\tif (registry.getApiKey(provider)) {\n\t\treturn true;\n\t}\n\t// Check environment variables\n\tif (getApiKeyFromEnv(provider)) {\n\t\treturn true;\n\t}\n\t// Gateway UI / CLI store keys in auth-profiles.json (async CredentialResolver); sync path for fallback list\n\treturn hasProviderAuthOnDiskSync(provider);\n}\n\nexport async function isProviderConfigured(provider: string): Promise<boolean> {\n if (getProviderRegistry().has(provider)) return true;\n\n // Check registry first for custom providers (from models.json)\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return true;\n }\n return await hasCredentials(provider);\n}\n\n/** Where runtime {@link getApiKey} resolves the key from (no secret values). */\nexport type ProviderActiveKeySource = 'none' | 'agent' | 'gateway' | 'oauth' | 'env' | 'models_json' | 'extension';\n\nexport async function getProviderActiveKeySource(provider: string): Promise<ProviderActiveKeySource> {\n if (getProviderRegistry().has(provider)) return 'extension';\n\n const resolver = new CredentialResolver();\n const fromCredentials = await resolver.resolveApiKeySource(provider);\n if (fromCredentials === 'agent') return 'agent';\n if (fromCredentials === 'global') return 'gateway';\n if (fromCredentials === 'oauth') return 'oauth';\n if (fromCredentials === 'env') return 'env';\n\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return 'models_json';\n }\n\n return 'none';\n}\n\nexport async function getConfiguredProviders(): Promise<string[]> {\n\tconst allProviders = getAllProviders();\n\tconst configured: string[] = [];\n\tfor (const p of allProviders) {\n\t\tif (await isProviderConfigured(p)) {\n\t\t\tconfigured.push(p);\n\t\t}\n\t}\n\treturn configured;\n}\n\nexport function getAllModels(): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst registryModels = registry.getAll();\n\tconst pluginProviders = getProviderRegistry().listAll();\n\tif (pluginProviders.length === 0) return registryModels;\n\n\tconst existingIds = new Set(registryModels.map(m => `${m.provider}/${m.id}`));\n\tconst merged: Model<Api>[] = [...registryModels];\n\tfor (const plugin of pluginProviders) {\n\t\tfor (const model of plugin.models) {\n\t\t\tconst compositeId = `${plugin.id}/${model.id}`;\n\t\t\tif (!existingIds.has(compositeId)) {\n\t\t\t\tmerged.push(pluginModelToModel(plugin.id, model));\n\t\t\t\texistingIds.add(compositeId);\n\t\t\t}\n\t\t}\n\t}\n\treturn merged;\n}\n\nexport async function getAvailableModels(): Promise<readonly Model<Api>[]> {\n\tconst allModels = getAllModels();\n\tconst pluginRegistry = getProviderRegistry();\n\tconst available: Model<Api>[] = [];\n\n\tfor (const model of allModels) {\n\t\tif (pluginRegistry.has(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t} else if (await isProviderConfigured(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t}\n\t}\n\treturn available;\n}\n\nexport type { Model, Api } from '@mariozechner/pi-ai';\n\nexport type ProviderCategory = 'common' | 'specialty' | 'oauth' | 'enterprise' | 'extension';\n\nexport interface ProviderMeta {\n name: string;\n category: ProviderCategory;\n supportsOAuth?: boolean;\n supportsApiKey?: boolean;\n}\n\nexport const PROVIDER_META: Record<string, ProviderMeta> = {\n 'openai': { name: 'OpenAI (GPT-4, o1, o3)', category: 'common', supportsApiKey: true },\n 'anthropic': { name: 'Anthropic Claude', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'deepseek': { name: 'DeepSeek', category: 'common', supportsApiKey: true },\n 'google': { name: 'Google Gemini', category: 'common', supportsApiKey: true },\n 'groq': { name: 'Groq (Fast Inference)', category: 'common', supportsApiKey: true },\n 'minimax': { name: 'MiniMax', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'minimax-cn': { name: 'MiniMax CN', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'kimi-coding': { name: 'Kimi For Coding', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'xai': { name: 'xAI (Grok)', category: 'specialty', supportsApiKey: true },\n 'mistral': { name: 'Mistral AI', category: 'specialty', supportsApiKey: true },\n 'cerebras': { name: 'Cerebras', category: 'specialty', supportsApiKey: true },\n 'openrouter': { name: 'OpenRouter (Multi-provider)', category: 'specialty', supportsApiKey: true },\n 'huggingface': { name: 'Hugging Face', category: 'specialty', supportsApiKey: true },\n 'opencode': { name: 'OpenCode', category: 'specialty', supportsApiKey: true },\n 'opencode-go': { name: 'OpenCode Go', category: 'specialty', supportsApiKey: true },\n /** DashScope (Alibaba) — image, speech, STT; not an LLM KnownProvider. */\n 'dashscope': { name: 'DashScope (Alibaba)', category: 'specialty', supportsApiKey: true },\n /** International GLM (api.z.ai). Auth: API key (ZAI_API_KEY); no published OAuth for this HTTP API. */\n 'zai': { name: 'Zhipu GLM (International · z.ai)', category: 'common', supportsApiKey: true },\n 'amazon-bedrock': { name: 'Amazon Bedrock', category: 'enterprise', supportsApiKey: true },\n 'azure-openai-responses': { name: 'Azure OpenAI', category: 'enterprise', supportsApiKey: true },\n 'google-vertex': { name: 'Google Vertex AI', category: 'enterprise', supportsApiKey: true },\n 'vercel-ai-gateway': { name: 'Vercel AI Gateway', category: 'enterprise', supportsApiKey: true },\n 'github-copilot': { name: 'GitHub Copilot (OAuth)', category: 'oauth', supportsOAuth: true },\n 'openai-codex': { name: 'OpenAI Codex (OAuth)', category: 'oauth', supportsOAuth: true },\n 'google-gemini-cli': { name: 'Google Gemini CLI (OAuth)', category: 'oauth', supportsOAuth: true },\n 'google-antigravity': { name: 'Google Antigravity (OAuth)', category: 'oauth', supportsOAuth: true },\n};\n\nexport function getSortedProviders(): string[] {\n const all = getAllProviders();\n const catOrder: Record<ProviderCategory, number> = { common: 0, specialty: 1, enterprise: 2, oauth: 3, extension: 4 };\n const pluginRegistry = getProviderRegistry();\n\n return [...all].sort((a, b) => {\n const catA = pluginRegistry.has(a) ? 'extension' : (PROVIDER_META[a]?.category ?? 'specialty');\n const catB = pluginRegistry.has(b) ? 'extension' : (PROVIDER_META[b]?.category ?? 'specialty');\n if (catOrder[catA] !== catOrder[catB]) {\n return catOrder[catA] - catOrder[catB];\n }\n return a.localeCompare(b);\n });\n}\n\nexport function getProviderDisplayName(provider: string): string {\n const plugin = getProviderRegistry().get(provider);\n if (plugin) return plugin.name;\n return PROVIDER_META[provider]?.name || provider;\n}\n\nexport function providerSupportsOAuth(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsOAuth ?? false;\n}\n\nexport function providerSupportsApiKey(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsApiKey ?? true;\n}\n\n// ============================================\n// Dynamic Default Model Resolution\n// ============================================\n\n/** Preferred default model when no explicit model is configured. */\nconst DEFAULT_FALLBACK_MODEL = 'deepseek/deepseek-v4-flash';\n\n/**\n * Get a default model reference.\n * Priority:\n * 1. Explicitly configured model in agents.defaults.model (if set and available)\n * 2. Default fallback: deepseek/deepseek-v4-flash\n */\nexport async function getDefaultModel(config?: Config | null | undefined): Promise<string> {\n const defaultModel = config?.agents?.defaults?.model;\n if (defaultModel) {\n const modelRef = typeof defaultModel === 'string' ? defaultModel : defaultModel.primary;\n if (modelRef) {\n const availableModels = await getAvailableModels();\n const configured = availableModels.find(m => \n `${m.provider}/${m.id}` === modelRef ||\n m.id === modelRef\n );\n if (configured) {\n return `${configured.provider}/${configured.id}`;\n }\n return modelRef;\n }\n }\n\n return DEFAULT_FALLBACK_MODEL;\n}\n\n/**\n * Synchronous default model resolution for constructors and sync code paths.\n * Uses catalog/registry only (no async credential checks).\n *\n * When no model is explicitly configured, returns the preferred default\n * (`deepseek/deepseek-v4-flash`) rather than picking an arbitrary first\n * model from the full catalog.\n */\nexport function getDefaultModelSync(config?: Config | null | undefined): string {\n const defaultModel = config?.agents?.defaults?.model;\n if (defaultModel) {\n const modelRef = typeof defaultModel === 'string' ? defaultModel : defaultModel.primary;\n if (modelRef) {\n return modelRef;\n }\n }\n\n return DEFAULT_FALLBACK_MODEL;\n}\n\n// Re-export ModelRegistry for advanced use cases\nexport { ModelRegistry, getModelRegistry, resetModelRegistry } from './model-registry.js';\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xopcai/xopc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"description": "Personal AI assistant: CLI, gateway (HTTP/WebSocket + React console), Telegram and WeChat (Weixin) channels — TypeScript, 20+ LLM providers via pi-ai, extensions and skills.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -87,6 +87,7 @@
|
|
|
87
87
|
"proper-lockfile": "^4.1.2",
|
|
88
88
|
"qrcode-terminal": "^0.12.0",
|
|
89
89
|
"silk-wasm": "^3.7.1",
|
|
90
|
+
"thread-stream": "^4.0.0",
|
|
90
91
|
"undici": "^8.1.0",
|
|
91
92
|
"uuid": "^14.0.0",
|
|
92
93
|
"zod": "^4.3.6"
|