@uncensoredcode/openbridge 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/cli/dist/args.js +23 -2
- package/packages/runtime/dist/tool-name-aliases.js +2 -1
- package/packages/server/dist/bridge/chat-completions/chat-completion-service.js +24 -1
- package/packages/server/dist/bridge/stores/local-session-package-store.js +49 -2
- package/packages/server/dist/bridge/stores/session-package-store.d.ts +2 -0
- package/packages/server/dist/bridge/stores/session-package-store.js +58 -1
- package/packages/server/dist/cli/index.d.ts +9 -0
- package/packages/server/dist/cli/index.js +1 -0
- package/packages/server/dist/cli/run-bridge-server-cli.d.ts +92 -0
- package/packages/server/dist/cli/run-bridge-server-cli.js +973 -46
- package/packages/server/dist/client/bridge-api-client.d.ts +81 -1
- package/packages/server/dist/client/bridge-api-client.js +184 -1
- package/packages/server/dist/client/index.d.ts +39 -1
- package/packages/server/dist/client/index.js +20 -1
package/package.json
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
const DEFAULT_BASE_URL = "http://127.0.0.1:4318";
|
|
2
|
-
const SERVER_SUBCOMMANDS = new Set([
|
|
2
|
+
const SERVER_SUBCOMMANDS = new Set([
|
|
3
|
+
"start",
|
|
4
|
+
"status",
|
|
5
|
+
"stop",
|
|
6
|
+
"logs",
|
|
7
|
+
"chat",
|
|
8
|
+
"live-canary",
|
|
9
|
+
"clear-session-vault",
|
|
10
|
+
"providers",
|
|
11
|
+
"models",
|
|
12
|
+
"sessions"
|
|
13
|
+
]);
|
|
3
14
|
function parseBridgeCliArgs(input) {
|
|
4
15
|
const env = input.env ?? process.env;
|
|
5
16
|
const args = [...input.argv];
|
|
@@ -55,8 +66,14 @@ function getBridgeCliHelpText() {
|
|
|
55
66
|
"openbridge",
|
|
56
67
|
"",
|
|
57
68
|
"Usage:",
|
|
58
|
-
" openbridge start [--host <host>] [--port <port>] [--token <token>]",
|
|
69
|
+
" openbridge start [--host <host>] [--port <port>] [--token <token>] [--foreground]",
|
|
70
|
+
" openbridge status [--state-root <path>]",
|
|
71
|
+
" openbridge stop [--state-root <path>]",
|
|
72
|
+
" openbridge logs [--follow] [--lines <count>] [--state-root <path>]",
|
|
59
73
|
" openbridge health [--base-url <url>]",
|
|
74
|
+
" openbridge providers <list|get|add|remove|enable|disable|import-session|session-status|clear-session> ...",
|
|
75
|
+
" openbridge models <list|add> ...",
|
|
76
|
+
" openbridge sessions <list|get|remove> ...",
|
|
60
77
|
" openbridge --session <id> [--input <text>] [--base-url <url>] [--provider <id>] [--model <id>] [--metadata <json>]",
|
|
61
78
|
" openbridge chat --model <id> --message <text> [--system <text>] [--base-url <url>] [--stream]",
|
|
62
79
|
" openbridge live-canary [--state-root <path>] [--provider <id>] [--model <id>]",
|
|
@@ -64,7 +81,11 @@ function getBridgeCliHelpText() {
|
|
|
64
81
|
"",
|
|
65
82
|
"Examples:",
|
|
66
83
|
" openbridge start",
|
|
84
|
+
" openbridge status",
|
|
85
|
+
" openbridge logs --follow",
|
|
67
86
|
" openbridge health",
|
|
87
|
+
" openbridge providers list",
|
|
88
|
+
" openbridge providers import-session provider-a --file ./session-package.json",
|
|
68
89
|
' openbridge --session demo "Read README.md"',
|
|
69
90
|
' openbridge --base-url http://127.0.0.1:4318 --session s1 --input "Run git status"'
|
|
70
91
|
].join("\n");
|
|
@@ -36,7 +36,7 @@ const EXPLICIT_CHAT_COMPLETION_HEADER_KEYS = [
|
|
|
36
36
|
"x-thread-id"
|
|
37
37
|
];
|
|
38
38
|
async function handleBridgeChatCompletionRequest(input) {
|
|
39
|
-
const body = input.body;
|
|
39
|
+
const body = normalizeRecoverableChatCompletionRequest(input.body);
|
|
40
40
|
assertSupportedChatCompletionRequest(body);
|
|
41
41
|
const resolvedModel = resolveBridgeModel(input.providerStore.list(), body.model);
|
|
42
42
|
if (!resolvedModel) {
|
|
@@ -300,6 +300,29 @@ const chatCompletionsRequestSchema = z
|
|
|
300
300
|
metadata: z.record(z.string(), z.unknown()).optional()
|
|
301
301
|
})
|
|
302
302
|
.strict();
|
|
303
|
+
function normalizeRecoverableChatCompletionRequest(body) {
|
|
304
|
+
const messages = normalizeRecoverableChatCompletionMessages(body.messages);
|
|
305
|
+
return messages === body.messages
|
|
306
|
+
? body
|
|
307
|
+
: {
|
|
308
|
+
...body,
|
|
309
|
+
messages
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function normalizeRecoverableChatCompletionMessages(messages) {
|
|
313
|
+
const normalized = [];
|
|
314
|
+
let changed = false;
|
|
315
|
+
for (const message of messages) {
|
|
316
|
+
const previous = normalized.at(-1);
|
|
317
|
+
if (message.role === "user" && previous?.role === "user") {
|
|
318
|
+
normalized[normalized.length - 1] = message;
|
|
319
|
+
changed = true;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
normalized.push(message);
|
|
323
|
+
}
|
|
324
|
+
return changed ? normalized : messages;
|
|
325
|
+
}
|
|
303
326
|
function assertSupportedChatCompletionRequest(body) {
|
|
304
327
|
if (body.n !== undefined && body.n !== 1) {
|
|
305
328
|
throw unsupportedChatCompletionsRequest("n", "Only n=1 is currently supported by the standalone bridge chat completions endpoint.");
|
|
@@ -5,7 +5,7 @@ import { z } from "zod";
|
|
|
5
5
|
import { bridgeApiErrorModule } from "../../shared/bridge-api-error.js";
|
|
6
6
|
import { providerStoreModule } from "./provider-store.js";
|
|
7
7
|
import { sessionPackageStoreModule } from "./session-package-store.js";
|
|
8
|
-
const { buildSessionPackageMetadata, cloneConfig, cloneInstalledProviderPackage, cloneProvider, cloneSessionPackage, cloneSessionPackageMetadata, inferProviderFromSessionPackage, installedProviderPackageSchema, sessionPackageDeleteResponseSchema, sessionPackageSchema, sessionPackageMetadataSchema } = sessionPackageStoreModule;
|
|
8
|
+
const { buildQwenConversationRequestBody, buildSessionPackageMetadata, cloneConfig, cloneInstalledProviderPackage, cloneProvider, cloneSessionPackage, cloneSessionPackageMetadata, inferProviderFromSessionPackage, installedProviderPackageSchema, sessionPackageDeleteResponseSchema, sessionPackageSchema, sessionPackageMetadataSchema } = sessionPackageStoreModule;
|
|
9
9
|
const { createProviderRequestSchema, providerDeleteResponseSchema, providerSchema } = providerStoreModule;
|
|
10
10
|
const { BridgeApiError } = bridgeApiErrorModule;
|
|
11
11
|
const SESSION_VAULT_VERSION = 1;
|
|
@@ -315,7 +315,7 @@ function createLocalSessionPackageStore(options) {
|
|
|
315
315
|
return null;
|
|
316
316
|
}
|
|
317
317
|
const entry = readVaultEntry(metadata);
|
|
318
|
-
return decryptInstalledPackage(entry, key);
|
|
318
|
+
return normalizeInstalledProviderPackage(decryptInstalledPackage(entry, key));
|
|
319
319
|
}
|
|
320
320
|
function readVaultIndex() {
|
|
321
321
|
if (!existsSync(indexPath)) {
|
|
@@ -372,6 +372,53 @@ function createLocalSessionPackageStore(options) {
|
|
|
372
372
|
return path.join(entriesPath, `${handle}.json`);
|
|
373
373
|
}
|
|
374
374
|
}
|
|
375
|
+
function normalizeInstalledProviderPackage(installed) {
|
|
376
|
+
const transport = readInstalledQwenTransport(installed.provider.config);
|
|
377
|
+
if (!transport) {
|
|
378
|
+
return installed;
|
|
379
|
+
}
|
|
380
|
+
const request = readInstalledTransportRequest(transport);
|
|
381
|
+
if (!request || !("body" in request)) {
|
|
382
|
+
return installed;
|
|
383
|
+
}
|
|
384
|
+
const normalizedBody = buildQwenConversationRequestBody(request.body);
|
|
385
|
+
if (JSON.stringify(normalizedBody) === JSON.stringify(request.body)) {
|
|
386
|
+
return installed;
|
|
387
|
+
}
|
|
388
|
+
return installedProviderPackageSchema.parse({
|
|
389
|
+
provider: {
|
|
390
|
+
...cloneProvider(installed.provider),
|
|
391
|
+
config: {
|
|
392
|
+
...cloneConfig(installed.provider.config),
|
|
393
|
+
transport: {
|
|
394
|
+
...transport,
|
|
395
|
+
request: {
|
|
396
|
+
...request,
|
|
397
|
+
body: normalizedBody
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
session: installed.session ? cloneSessionPackage(installed.session) : null
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
function readInstalledQwenTransport(config) {
|
|
406
|
+
const transport = typeof config.transport === "object" &&
|
|
407
|
+
config.transport !== null &&
|
|
408
|
+
!Array.isArray(config.transport)
|
|
409
|
+
? config.transport
|
|
410
|
+
: null;
|
|
411
|
+
const request = readInstalledTransportRequest(transport);
|
|
412
|
+
const url = typeof request?.url === "string" ? request.url.trim() : "";
|
|
413
|
+
return /^https:\/\/chat\.qwen\.ai\/api\/v2\/chat\/completions\b/u.test(url) ? transport : null;
|
|
414
|
+
}
|
|
415
|
+
function readInstalledTransportRequest(transport) {
|
|
416
|
+
return typeof transport?.request === "object" &&
|
|
417
|
+
transport.request !== null &&
|
|
418
|
+
!Array.isArray(transport.request)
|
|
419
|
+
? transport.request
|
|
420
|
+
: null;
|
|
421
|
+
}
|
|
375
422
|
function encryptInstalledPackage(metadata, value, key) {
|
|
376
423
|
const iv = crypto.randomBytes(12);
|
|
377
424
|
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
|
@@ -165,6 +165,7 @@ declare function inferProviderFromSessionPackage(input: {
|
|
|
165
165
|
createdAt: string;
|
|
166
166
|
updatedAt: string;
|
|
167
167
|
};
|
|
168
|
+
declare function buildQwenConversationRequestBody(requestBody: unknown): unknown;
|
|
168
169
|
export declare const sessionPackageStoreModule: {
|
|
169
170
|
sessionPackageSchema: z.ZodObject<{
|
|
170
171
|
schemaVersion: z.ZodOptional<z.ZodNumber>;
|
|
@@ -274,6 +275,7 @@ export declare const sessionPackageStoreModule: {
|
|
|
274
275
|
}, z.core.$strict>>;
|
|
275
276
|
}, z.core.$strict>;
|
|
276
277
|
createInMemorySessionPackageStore: typeof createInMemorySessionPackageStore;
|
|
278
|
+
buildQwenConversationRequestBody: typeof buildQwenConversationRequestBody;
|
|
277
279
|
buildSessionPackageStatus: typeof buildSessionPackageStatus;
|
|
278
280
|
cloneProvider: typeof cloneProvider;
|
|
279
281
|
cloneConfig: typeof cloneConfig;
|
|
@@ -416,7 +416,9 @@ function inferQwenConversationTransport(selectedRequest, value) {
|
|
|
416
416
|
method: String(selectedRequest.method).toUpperCase(),
|
|
417
417
|
url: "https://chat.qwen.ai/api/v2/chat/completions?chat_id={{conversationId}}",
|
|
418
418
|
headers: {},
|
|
419
|
-
...(requestBody === undefined
|
|
419
|
+
...(requestBody === undefined
|
|
420
|
+
? {}
|
|
421
|
+
: { body: buildQwenConversationRequestBody(requestBody) })
|
|
420
422
|
},
|
|
421
423
|
response: {
|
|
422
424
|
contentPaths: DEFAULT_SSE_CONTENT_PATHS,
|
|
@@ -926,6 +928,60 @@ function buildQwenBootstrapRequestBody(selectedRequest) {
|
|
|
926
928
|
project_id: projectId
|
|
927
929
|
};
|
|
928
930
|
}
|
|
931
|
+
function buildQwenConversationRequestBody(requestBody) {
|
|
932
|
+
if (typeof requestBody !== "object" || requestBody === null || Array.isArray(requestBody)) {
|
|
933
|
+
return requestBody;
|
|
934
|
+
}
|
|
935
|
+
const base = structuredClone(requestBody);
|
|
936
|
+
if ("chat_id" in base) {
|
|
937
|
+
base.chat_id = "{{conversationId}}";
|
|
938
|
+
}
|
|
939
|
+
if ("model" in base) {
|
|
940
|
+
base.model = "{{modelId}}";
|
|
941
|
+
}
|
|
942
|
+
if ("timestamp" in base) {
|
|
943
|
+
base.timestamp = "{{unixTimestampSec}}";
|
|
944
|
+
}
|
|
945
|
+
if ("parent_id" in base) {
|
|
946
|
+
base.parent_id = "{{parentIdOrNull}}";
|
|
947
|
+
}
|
|
948
|
+
if (Array.isArray(base.messages) && base.messages.length > 0) {
|
|
949
|
+
base.messages = base.messages.map((message, index) => index === 0 ? buildQwenConversationUserMessage(message) : message);
|
|
950
|
+
}
|
|
951
|
+
return base;
|
|
952
|
+
}
|
|
953
|
+
function buildQwenConversationUserMessage(message) {
|
|
954
|
+
if (typeof message !== "object" || message === null || Array.isArray(message)) {
|
|
955
|
+
return {
|
|
956
|
+
fid: "{{messageId}}",
|
|
957
|
+
role: "user",
|
|
958
|
+
content: "{{prompt}}"
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
const nextMessage = structuredClone(message);
|
|
962
|
+
nextMessage.fid = "{{messageId}}";
|
|
963
|
+
nextMessage.role = "user";
|
|
964
|
+
nextMessage.content = "{{prompt}}";
|
|
965
|
+
if ("timestamp" in nextMessage) {
|
|
966
|
+
nextMessage.timestamp = "{{unixTimestampSec}}";
|
|
967
|
+
}
|
|
968
|
+
if ("models" in nextMessage) {
|
|
969
|
+
nextMessage.models = ["{{modelId}}"];
|
|
970
|
+
}
|
|
971
|
+
if ("parentId" in nextMessage) {
|
|
972
|
+
nextMessage.parentId = "{{parentIdOrNull}}";
|
|
973
|
+
}
|
|
974
|
+
if ("parent_id" in nextMessage) {
|
|
975
|
+
nextMessage.parent_id = "{{parentIdOrNull}}";
|
|
976
|
+
}
|
|
977
|
+
if ("childrenIds" in nextMessage && Array.isArray(nextMessage.childrenIds)) {
|
|
978
|
+
nextMessage.childrenIds = [];
|
|
979
|
+
}
|
|
980
|
+
if ("children_ids" in nextMessage && Array.isArray(nextMessage.children_ids)) {
|
|
981
|
+
nextMessage.children_ids = [];
|
|
982
|
+
}
|
|
983
|
+
return nextMessage;
|
|
984
|
+
}
|
|
929
985
|
function buildOpenAiConversationRequestBody(requestBody) {
|
|
930
986
|
const base = requestBody ? structuredClone(requestBody) : {};
|
|
931
987
|
const capturedMessage = Array.isArray(requestBody?.messages) &&
|
|
@@ -1516,6 +1572,7 @@ export const sessionPackageStoreModule = {
|
|
|
1516
1572
|
sessionPackageMetadataSchema,
|
|
1517
1573
|
installedProviderPackageSchema,
|
|
1518
1574
|
createInMemorySessionPackageStore,
|
|
1575
|
+
buildQwenConversationRequestBody,
|
|
1519
1576
|
buildSessionPackageStatus,
|
|
1520
1577
|
cloneProvider,
|
|
1521
1578
|
cloneConfig,
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
export declare const cliModule: {
|
|
2
|
+
buildDetachedServerLaunchCommand: (input: {
|
|
3
|
+
scriptPath: string;
|
|
4
|
+
argv: string[];
|
|
5
|
+
execPath: string;
|
|
6
|
+
execArgv: string[];
|
|
7
|
+
}) => {
|
|
8
|
+
command: string;
|
|
9
|
+
args: string[];
|
|
10
|
+
};
|
|
2
11
|
getBridgeServerCliHelpText: () => string;
|
|
3
12
|
parseBridgeServerCliArgs: (input: {
|
|
4
13
|
argv: string[];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { runBridgeServerCliModule } from "./run-bridge-server-cli.js";
|
|
2
2
|
export const cliModule = {
|
|
3
|
+
buildDetachedServerLaunchCommand: runBridgeServerCliModule.buildDetachedServerLaunchCommand,
|
|
3
4
|
getBridgeServerCliHelpText: runBridgeServerCliModule.getBridgeServerCliHelpText,
|
|
4
5
|
parseBridgeServerCliArgs: runBridgeServerCliModule.parseBridgeServerCliArgs,
|
|
5
6
|
runBridgeServerCli: runBridgeServerCliModule.runBridgeServerCli
|
|
@@ -8,6 +8,77 @@ type BridgeServerCliCommand = {
|
|
|
8
8
|
} | {
|
|
9
9
|
kind: "serve";
|
|
10
10
|
config: BridgeServerConfig;
|
|
11
|
+
foreground: boolean;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "status";
|
|
14
|
+
config: BridgeServerConfig;
|
|
15
|
+
} | {
|
|
16
|
+
kind: "stop";
|
|
17
|
+
config: BridgeServerConfig;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "logs";
|
|
20
|
+
config: BridgeServerConfig;
|
|
21
|
+
follow: boolean;
|
|
22
|
+
lines: number;
|
|
23
|
+
} | {
|
|
24
|
+
kind: "providers-list";
|
|
25
|
+
baseUrl: string;
|
|
26
|
+
} | {
|
|
27
|
+
kind: "providers-get";
|
|
28
|
+
baseUrl: string;
|
|
29
|
+
id: string;
|
|
30
|
+
} | {
|
|
31
|
+
kind: "providers-add";
|
|
32
|
+
baseUrl: string;
|
|
33
|
+
id: string;
|
|
34
|
+
providerKind: string;
|
|
35
|
+
label: string;
|
|
36
|
+
enabled: boolean;
|
|
37
|
+
config: Record<string, unknown> | undefined;
|
|
38
|
+
} | {
|
|
39
|
+
kind: "providers-remove";
|
|
40
|
+
baseUrl: string;
|
|
41
|
+
id: string;
|
|
42
|
+
} | {
|
|
43
|
+
kind: "providers-enable";
|
|
44
|
+
baseUrl: string;
|
|
45
|
+
id: string;
|
|
46
|
+
} | {
|
|
47
|
+
kind: "providers-disable";
|
|
48
|
+
baseUrl: string;
|
|
49
|
+
id: string;
|
|
50
|
+
} | {
|
|
51
|
+
kind: "providers-import-session";
|
|
52
|
+
baseUrl: string;
|
|
53
|
+
id: string;
|
|
54
|
+
filePath?: string;
|
|
55
|
+
} | {
|
|
56
|
+
kind: "providers-session-status";
|
|
57
|
+
baseUrl: string;
|
|
58
|
+
id: string;
|
|
59
|
+
} | {
|
|
60
|
+
kind: "providers-clear-session";
|
|
61
|
+
baseUrl: string;
|
|
62
|
+
id: string;
|
|
63
|
+
} | {
|
|
64
|
+
kind: "models-list";
|
|
65
|
+
baseUrl: string;
|
|
66
|
+
} | {
|
|
67
|
+
kind: "models-add";
|
|
68
|
+
baseUrl: string;
|
|
69
|
+
provider: string;
|
|
70
|
+
model: string;
|
|
71
|
+
} | {
|
|
72
|
+
kind: "sessions-list";
|
|
73
|
+
baseUrl: string;
|
|
74
|
+
} | {
|
|
75
|
+
kind: "sessions-get";
|
|
76
|
+
baseUrl: string;
|
|
77
|
+
id: string;
|
|
78
|
+
} | {
|
|
79
|
+
kind: "sessions-remove";
|
|
80
|
+
baseUrl: string;
|
|
81
|
+
id: string;
|
|
11
82
|
} | {
|
|
12
83
|
kind: "clear-session-vault";
|
|
13
84
|
config: BridgeServerConfig;
|
|
@@ -39,6 +110,20 @@ type RunBridgeServerCliInput = {
|
|
|
39
110
|
keyPath: string;
|
|
40
111
|
stdin: NodeJS.ReadStream;
|
|
41
112
|
}) => Promise<string>;
|
|
113
|
+
spawnDetachedServerProcess?: (input: SpawnDetachedServerProcessInput) => Promise<SpawnDetachedServerProcessResult>;
|
|
114
|
+
};
|
|
115
|
+
type SpawnDetachedServerProcessInput = {
|
|
116
|
+
argv: string[];
|
|
117
|
+
env: NodeJS.ProcessEnv;
|
|
118
|
+
logPath: string;
|
|
119
|
+
cwd: string;
|
|
120
|
+
};
|
|
121
|
+
type SpawnDetachedServerProcessResult = {
|
|
122
|
+
pid: number;
|
|
123
|
+
};
|
|
124
|
+
type DetachedServerLaunchCommand = {
|
|
125
|
+
command: string;
|
|
126
|
+
args: string[];
|
|
42
127
|
};
|
|
43
128
|
declare function runBridgeServerCli(input: RunBridgeServerCliInput): Promise<number>;
|
|
44
129
|
declare function parseBridgeServerCliArgs(input: {
|
|
@@ -46,7 +131,14 @@ declare function parseBridgeServerCliArgs(input: {
|
|
|
46
131
|
env?: NodeJS.ProcessEnv;
|
|
47
132
|
}): BridgeServerCliCommand;
|
|
48
133
|
declare function getBridgeServerCliHelpText(): string;
|
|
134
|
+
declare function buildDetachedServerLaunchCommand(input: {
|
|
135
|
+
scriptPath: string;
|
|
136
|
+
argv: string[];
|
|
137
|
+
execPath: string;
|
|
138
|
+
execArgv: string[];
|
|
139
|
+
}): DetachedServerLaunchCommand;
|
|
49
140
|
export declare const runBridgeServerCliModule: {
|
|
141
|
+
buildDetachedServerLaunchCommand: typeof buildDetachedServerLaunchCommand;
|
|
50
142
|
runBridgeServerCli: typeof runBridgeServerCli;
|
|
51
143
|
parseBridgeServerCliArgs: typeof parseBridgeServerCliArgs;
|
|
52
144
|
getBridgeServerCliHelpText: typeof getBridgeServerCliHelpText;
|