@onyx.dev/onyx-database 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -0
- package/dist/{aggregates-DodZNu9-.d.cts → aggregates-BJT5DGGX.d.cts} +308 -1
- package/dist/{aggregates-DodZNu9-.d.ts → aggregates-BJT5DGGX.d.ts} +308 -1
- package/dist/edge.cjs +267 -11
- package/dist/edge.cjs.map +1 -1
- package/dist/edge.d.cts +2 -2
- package/dist/edge.d.ts +2 -2
- package/dist/edge.js +267 -11
- package/dist/edge.js.map +1 -1
- package/dist/gen/cli/generate.cjs +269 -11
- package/dist/gen/cli/generate.cjs.map +1 -1
- package/dist/index.cjs +269 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +269 -11
- package/dist/index.js.map +1 -1
- package/dist/schema/cli/schema.cjs +271 -11
- package/dist/schema/cli/schema.cjs.map +1 -1
- package/package.json +1 -1
|
@@ -814,10 +814,18 @@ interface RetryOptions {
|
|
|
814
814
|
}
|
|
815
815
|
interface OnyxConfig {
|
|
816
816
|
baseUrl?: string;
|
|
817
|
+
/**
|
|
818
|
+
* Base URL for AI endpoints. Defaults to https://ai.onyx.dev.
|
|
819
|
+
*/
|
|
820
|
+
aiBaseUrl?: string;
|
|
817
821
|
databaseId?: string;
|
|
818
822
|
apiKey?: string;
|
|
819
823
|
apiSecret?: string;
|
|
820
824
|
fetch?: FetchImpl;
|
|
825
|
+
/**
|
|
826
|
+
* Default AI model when using shorthand chat calls (`db.chat('...')`). Defaults to `onyx`.
|
|
827
|
+
*/
|
|
828
|
+
defaultModel?: string;
|
|
821
829
|
/**
|
|
822
830
|
* Default partition for queries, `findById`, and deletes when removing by
|
|
823
831
|
* primary key. Saves rely on the entity's partition field instead.
|
|
@@ -840,7 +848,306 @@ interface OnyxConfig {
|
|
|
840
848
|
*/
|
|
841
849
|
retry?: RetryOptions;
|
|
842
850
|
}
|
|
851
|
+
interface AiRequestOptions {
|
|
852
|
+
/**
|
|
853
|
+
* Optional database scope for AI calls. Defaults to the configured databaseId.
|
|
854
|
+
*/
|
|
855
|
+
databaseId?: string;
|
|
856
|
+
}
|
|
857
|
+
type AiChatRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
858
|
+
interface AiToolCallFunction {
|
|
859
|
+
name: string;
|
|
860
|
+
arguments: string;
|
|
861
|
+
}
|
|
862
|
+
interface AiToolCall {
|
|
863
|
+
id?: string | null;
|
|
864
|
+
type?: string | null;
|
|
865
|
+
function: AiToolCallFunction;
|
|
866
|
+
}
|
|
867
|
+
interface AiChatMessage {
|
|
868
|
+
role: AiChatRole;
|
|
869
|
+
content?: string | null;
|
|
870
|
+
tool_calls?: AiToolCall[] | null;
|
|
871
|
+
tool_call_id?: string | null;
|
|
872
|
+
name?: string | null;
|
|
873
|
+
}
|
|
874
|
+
interface AiToolFunction {
|
|
875
|
+
name: string;
|
|
876
|
+
description?: string | null;
|
|
877
|
+
parameters?: Record<string, unknown> | null;
|
|
878
|
+
}
|
|
879
|
+
interface AiTool {
|
|
880
|
+
type: string;
|
|
881
|
+
function: AiToolFunction;
|
|
882
|
+
}
|
|
883
|
+
type AiToolChoice = 'none' | 'auto' | {
|
|
884
|
+
type: 'function';
|
|
885
|
+
function: {
|
|
886
|
+
name: string;
|
|
887
|
+
};
|
|
888
|
+
} | null;
|
|
889
|
+
interface AiChatCompletionRequest {
|
|
890
|
+
model: string;
|
|
891
|
+
messages: AiChatMessage[];
|
|
892
|
+
stream?: boolean;
|
|
893
|
+
temperature?: number | null;
|
|
894
|
+
top_p?: number | null;
|
|
895
|
+
max_tokens?: number | null;
|
|
896
|
+
metadata?: Record<string, unknown>;
|
|
897
|
+
tools?: AiTool[];
|
|
898
|
+
tool_choice?: AiToolChoice;
|
|
899
|
+
user?: string | null;
|
|
900
|
+
}
|
|
901
|
+
interface AiChatCompletionUsage {
|
|
902
|
+
prompt_tokens?: number | null;
|
|
903
|
+
completion_tokens?: number | null;
|
|
904
|
+
total_tokens?: number | null;
|
|
905
|
+
}
|
|
906
|
+
interface AiChatCompletionChoice {
|
|
907
|
+
index: number;
|
|
908
|
+
message: AiChatMessage;
|
|
909
|
+
finish_reason?: string | null;
|
|
910
|
+
}
|
|
911
|
+
interface AiChatCompletionResponse {
|
|
912
|
+
id: string;
|
|
913
|
+
object: string;
|
|
914
|
+
created: number;
|
|
915
|
+
model: string;
|
|
916
|
+
choices: AiChatCompletionChoice[];
|
|
917
|
+
usage?: AiChatCompletionUsage;
|
|
918
|
+
}
|
|
919
|
+
interface AiChatCompletionChunkDelta {
|
|
920
|
+
role?: AiChatRole | null;
|
|
921
|
+
content?: string | null;
|
|
922
|
+
tool_calls?: AiToolCall[] | null;
|
|
923
|
+
tool_call_id?: string | null;
|
|
924
|
+
name?: string | null;
|
|
925
|
+
}
|
|
926
|
+
interface AiChatCompletionChunkChoice {
|
|
927
|
+
index: number;
|
|
928
|
+
delta: AiChatCompletionChunkDelta;
|
|
929
|
+
finish_reason?: string | null;
|
|
930
|
+
}
|
|
931
|
+
interface AiChatCompletionChunk {
|
|
932
|
+
id: string;
|
|
933
|
+
object: string;
|
|
934
|
+
created: number;
|
|
935
|
+
model?: string | null;
|
|
936
|
+
choices: AiChatCompletionChunkChoice[];
|
|
937
|
+
}
|
|
938
|
+
interface AiChatCompletionStream extends AsyncIterable<AiChatCompletionChunk> {
|
|
939
|
+
cancel(): void;
|
|
940
|
+
}
|
|
941
|
+
interface AiChatOptions extends AiRequestOptions {
|
|
942
|
+
/**
|
|
943
|
+
* Model to use for the shorthand `db.chat()` call. Defaults to config.defaultModel or `onyx`.
|
|
944
|
+
*/
|
|
945
|
+
model?: string;
|
|
946
|
+
/**
|
|
947
|
+
* Role for the constructed message. Defaults to `user`.
|
|
948
|
+
*/
|
|
949
|
+
role?: AiChatRole;
|
|
950
|
+
/**
|
|
951
|
+
* Temperature for the completion. Omit to use the service default.
|
|
952
|
+
*/
|
|
953
|
+
temperature?: number | null;
|
|
954
|
+
/**
|
|
955
|
+
* Enable SSE streaming. Defaults to `false`.
|
|
956
|
+
*/
|
|
957
|
+
stream?: boolean;
|
|
958
|
+
/**
|
|
959
|
+
* When true, return the raw completion response instead of the first message content.
|
|
960
|
+
*/
|
|
961
|
+
raw?: boolean;
|
|
962
|
+
}
|
|
963
|
+
interface AiChatClient {
|
|
964
|
+
create(request: AiChatCompletionRequest & {
|
|
965
|
+
stream?: false;
|
|
966
|
+
}, options?: AiRequestOptions): Promise<AiChatCompletionResponse>;
|
|
967
|
+
create(request: AiChatCompletionRequest & {
|
|
968
|
+
stream: true;
|
|
969
|
+
}, options?: AiRequestOptions): Promise<AiChatCompletionStream>;
|
|
970
|
+
create(request: AiChatCompletionRequest, options?: AiRequestOptions): Promise<AiChatCompletionResponse | AiChatCompletionStream>;
|
|
971
|
+
}
|
|
972
|
+
interface AiScriptApprovalRequest {
|
|
973
|
+
script: string;
|
|
974
|
+
}
|
|
975
|
+
interface AiScriptApprovalResponse {
|
|
976
|
+
normalizedScript: string;
|
|
977
|
+
expiresAtIso: string;
|
|
978
|
+
requiresApproval: boolean;
|
|
979
|
+
findings?: string;
|
|
980
|
+
}
|
|
981
|
+
interface AiModelsResponse {
|
|
982
|
+
object: string;
|
|
983
|
+
data: AiModel[];
|
|
984
|
+
}
|
|
985
|
+
interface AiModel {
|
|
986
|
+
id: string;
|
|
987
|
+
object: string;
|
|
988
|
+
created: number;
|
|
989
|
+
owned_by: string;
|
|
990
|
+
}
|
|
991
|
+
interface AiErrorResponse {
|
|
992
|
+
error?: string | {
|
|
993
|
+
message?: string;
|
|
994
|
+
[key: string]: unknown;
|
|
995
|
+
} | null;
|
|
996
|
+
}
|
|
997
|
+
interface AiClient {
|
|
998
|
+
/**
|
|
999
|
+
* Run a chat completion. Accepts shorthand strings or full requests.
|
|
1000
|
+
*
|
|
1001
|
+
* @example
|
|
1002
|
+
* ```ts
|
|
1003
|
+
* const quick = await db.ai.chat('Summarize last week.'); // returns first message content
|
|
1004
|
+
* const completion = await db.ai.chat(
|
|
1005
|
+
* { model: 'onyx-chat', messages: [{ role: 'user', content: 'Summarize last week.' }] },
|
|
1006
|
+
* { databaseId: 'db1', raw: true }, // returns full response
|
|
1007
|
+
* );
|
|
1008
|
+
* ```
|
|
1009
|
+
*/
|
|
1010
|
+
chat(content: string, options?: AiChatOptions & {
|
|
1011
|
+
stream?: false;
|
|
1012
|
+
raw?: false | undefined;
|
|
1013
|
+
}): Promise<string>;
|
|
1014
|
+
chat(content: string, options: AiChatOptions & {
|
|
1015
|
+
stream: true;
|
|
1016
|
+
}): Promise<AiChatCompletionStream>;
|
|
1017
|
+
chat(content: string, options: AiChatOptions & {
|
|
1018
|
+
raw: true;
|
|
1019
|
+
}): Promise<AiChatCompletionResponse | AiChatCompletionStream>;
|
|
1020
|
+
chat(request: AiChatCompletionRequest & {
|
|
1021
|
+
stream?: false;
|
|
1022
|
+
}, options?: AiRequestOptions): Promise<AiChatCompletionResponse>;
|
|
1023
|
+
chat(request: AiChatCompletionRequest & {
|
|
1024
|
+
stream: true;
|
|
1025
|
+
}, options?: AiRequestOptions): Promise<AiChatCompletionStream>;
|
|
1026
|
+
chat(request: AiChatCompletionRequest, options?: AiRequestOptions): Promise<AiChatCompletionResponse | AiChatCompletionStream>;
|
|
1027
|
+
/**
|
|
1028
|
+
* Access the chat client for more control over streaming and cancellation.
|
|
1029
|
+
*/
|
|
1030
|
+
chatClient(): AiChatClient;
|
|
1031
|
+
/**
|
|
1032
|
+
* List available AI models.
|
|
1033
|
+
*
|
|
1034
|
+
* @example
|
|
1035
|
+
* ```ts
|
|
1036
|
+
* const models = await db.ai.getModels();
|
|
1037
|
+
* ```
|
|
1038
|
+
*/
|
|
1039
|
+
getModels(): Promise<AiModelsResponse>;
|
|
1040
|
+
/**
|
|
1041
|
+
* Retrieve a single AI model by ID.
|
|
1042
|
+
*
|
|
1043
|
+
* @example
|
|
1044
|
+
* ```ts
|
|
1045
|
+
* const model = await db.ai.getModel('onyx-chat');
|
|
1046
|
+
* ```
|
|
1047
|
+
*/
|
|
1048
|
+
getModel(modelId: string): Promise<AiModel>;
|
|
1049
|
+
/**
|
|
1050
|
+
* Request mutation approval for a script.
|
|
1051
|
+
*
|
|
1052
|
+
* @example
|
|
1053
|
+
* ```ts
|
|
1054
|
+
* const approval = await db.ai.requestScriptApproval({
|
|
1055
|
+
* script: "db.save({ id: 'u1', email: 'a@b.com' })"
|
|
1056
|
+
* });
|
|
1057
|
+
* ```
|
|
1058
|
+
*/
|
|
1059
|
+
requestScriptApproval(input: AiScriptApprovalRequest): Promise<AiScriptApprovalResponse>;
|
|
1060
|
+
}
|
|
843
1061
|
interface IOnyxDatabase<Schema = Record<string, unknown>> {
|
|
1062
|
+
/**
|
|
1063
|
+
* AI helpers (chat, models, script approvals) grouped under `db.ai`.
|
|
1064
|
+
*
|
|
1065
|
+
* @example
|
|
1066
|
+
* ```ts
|
|
1067
|
+
* const completion = await db.ai.chat({
|
|
1068
|
+
* model: 'onyx-chat',
|
|
1069
|
+
* messages: [{ role: 'user', content: 'Summarize last week.' }],
|
|
1070
|
+
* });
|
|
1071
|
+
* ```
|
|
1072
|
+
*/
|
|
1073
|
+
ai: AiClient;
|
|
1074
|
+
/**
|
|
1075
|
+
* Access OpenAI-compatible chat completions via `db.chat('...')` or `db.chat().create(...)`.
|
|
1076
|
+
*
|
|
1077
|
+
* @example
|
|
1078
|
+
* ```ts
|
|
1079
|
+
* const completion = await db.chat('Summarize last week.'); // returns first message content
|
|
1080
|
+
* ```
|
|
1081
|
+
*
|
|
1082
|
+
* @example
|
|
1083
|
+
* ```ts
|
|
1084
|
+
* const chat = db.chat();
|
|
1085
|
+
* const completion = await chat.create({
|
|
1086
|
+
* model: 'onyx-chat',
|
|
1087
|
+
* messages: [{ role: 'user', content: 'Summarize last week.' }],
|
|
1088
|
+
* });
|
|
1089
|
+
* ```
|
|
1090
|
+
*
|
|
1091
|
+
* @example
|
|
1092
|
+
* ```ts
|
|
1093
|
+
* const stream = await db
|
|
1094
|
+
* .chat()
|
|
1095
|
+
* .create({
|
|
1096
|
+
* model: 'onyx-chat',
|
|
1097
|
+
* stream: true,
|
|
1098
|
+
* messages: [{ role: 'user', content: 'Draft an onboarding checklist.' }],
|
|
1099
|
+
* });
|
|
1100
|
+
* for await (const chunk of stream) {
|
|
1101
|
+
* process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
|
|
1102
|
+
* }
|
|
1103
|
+
* ```
|
|
1104
|
+
*/
|
|
1105
|
+
chat(content: string, options?: AiChatOptions & {
|
|
1106
|
+
stream?: false;
|
|
1107
|
+
raw?: false | undefined;
|
|
1108
|
+
}): Promise<string>;
|
|
1109
|
+
chat(content: string, options: AiChatOptions & {
|
|
1110
|
+
stream: true;
|
|
1111
|
+
}): Promise<AiChatCompletionStream>;
|
|
1112
|
+
chat(content: string, options: AiChatOptions & {
|
|
1113
|
+
raw: true;
|
|
1114
|
+
}): Promise<AiChatCompletionResponse | AiChatCompletionStream>;
|
|
1115
|
+
chat(): AiChatClient;
|
|
1116
|
+
/**
|
|
1117
|
+
* List available AI models.
|
|
1118
|
+
*
|
|
1119
|
+
* @deprecated Prefer `db.ai.getModels()`.
|
|
1120
|
+
*
|
|
1121
|
+
* @example
|
|
1122
|
+
* ```ts
|
|
1123
|
+
* const models = await db.getModels();
|
|
1124
|
+
* ```
|
|
1125
|
+
*/
|
|
1126
|
+
getModels(): Promise<AiModelsResponse>;
|
|
1127
|
+
/**
|
|
1128
|
+
* Retrieve a single AI model by ID.
|
|
1129
|
+
*
|
|
1130
|
+
* @deprecated Prefer `db.ai.getModel(...)`.
|
|
1131
|
+
*
|
|
1132
|
+
* @example
|
|
1133
|
+
* ```ts
|
|
1134
|
+
* const model = await db.getModel('onyx-chat');
|
|
1135
|
+
* ```
|
|
1136
|
+
*/
|
|
1137
|
+
getModel(modelId: string): Promise<AiModel>;
|
|
1138
|
+
/**
|
|
1139
|
+
* Request mutation approval for a script.
|
|
1140
|
+
*
|
|
1141
|
+
* @deprecated Prefer `db.ai.requestScriptApproval(...)`.
|
|
1142
|
+
*
|
|
1143
|
+
* @example
|
|
1144
|
+
* ```ts
|
|
1145
|
+
* const approval = await db.requestScriptApproval({
|
|
1146
|
+
* script: "db.save({ id: 'u1', email: 'a@b.com' })"
|
|
1147
|
+
* });
|
|
1148
|
+
* ```
|
|
1149
|
+
*/
|
|
1150
|
+
requestScriptApproval(input: AiScriptApprovalRequest): Promise<AiScriptApprovalResponse>;
|
|
844
1151
|
/**
|
|
845
1152
|
* Begin a query against a table.
|
|
846
1153
|
*
|
|
@@ -1450,4 +1757,4 @@ declare const substring: (attribute: string, from: number, length: number) => st
|
|
|
1450
1757
|
declare const replace: (attribute: string, pattern: string, repl: string) => string;
|
|
1451
1758
|
declare const percentile: (attribute: string, p: number) => string;
|
|
1452
1759
|
|
|
1453
|
-
export {
|
|
1760
|
+
export { type SchemaTriggerChange as $, type AiRequestOptions as A, type SecretsListResponse as B, type SecretSaveRequest as C, type SchemaDataType as D, type SchemaIdentifierGenerator as E, type FullTextQuery as F, type SchemaIdentifier as G, type SchemaAttribute as H, type IOnyxDatabase as I, type SchemaIndexType as J, type SchemaIndex as K, type SchemaResolver as L, type SchemaTriggerEvent as M, type SchemaTrigger as N, type OnyxFacade as O, type SchemaEntity as P, QueryResults as Q, type RetryOptions as R, type SecretMetadata as S, type SchemaRevisionMetadata as T, type SchemaRevision as U, type SchemaHistoryEntry as V, type SchemaUpsertRequest as W, type SchemaValidationResult as X, type SchemaAttributeChange as Y, type SchemaIndexChange as Z, type SchemaResolverChange as _, type QueryResultsPromise as a, type SchemaTableDiff as a0, type SchemaDiff as a1, type QueryCriteriaOperator as a2, type LogicalOperator as a3, type Sort as a4, type StreamAction as a5, type OnyxDocument as a6, type FetchResponse as a7, type FetchImpl as a8, type QueryCriteria as a9, notLike as aA, contains as aB, containsIgnoreCase as aC, notContains as aD, notContainsIgnoreCase as aE, startsWith as aF, notStartsWith as aG, isNull as aH, notNull as aI, avg as aJ, sum as aK, count as aL, min as aM, max as aN, std as aO, variance as aP, median as aQ, upper as aR, lower as aS, substring as aT, replace as aU, percentile as aV, type QueryCondition as aa, type SelectQuery as ab, type UpdateQuery as ac, type QueryPage as ad, type IConditionBuilder as ae, type IQueryBuilder as af, type ISaveBuilder as ag, type ICascadeBuilder as ah, type ICascadeRelationshipBuilder as ai, asc as aj, desc as ak, eq as al, neq as am, inOp as an, within as ao, notIn as ap, notWithin as aq, between as ar, gt as as, gte as at, lt as au, lte as av, matches as aw, search as ax, notMatches as ay, like as az, type OnyxConfig as b, type AiChatRole as c, type AiToolCallFunction as d, type AiToolCall as e, type AiChatMessage as f, type AiToolFunction as g, type AiTool as h, type AiToolChoice as i, type AiChatCompletionRequest as j, type AiChatCompletionUsage as k, type AiChatCompletionChoice as l, type AiChatCompletionResponse as m, type AiChatCompletionChunkDelta as n, type AiChatCompletionChunkChoice as o, type AiChatCompletionChunk as p, type AiChatCompletionStream as q, type AiChatOptions as r, type AiChatClient as s, type AiScriptApprovalRequest as t, type AiScriptApprovalResponse as u, type AiModelsResponse as v, type AiModel as w, type AiErrorResponse as x, type AiClient as y, type SecretRecord as z };
|
package/dist/edge.cjs
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
// src/config/defaults.ts
|
|
4
4
|
var DEFAULT_BASE_URL = "https://api.onyx.dev";
|
|
5
|
+
var DEFAULT_AI_BASE_URL = "https://ai.onyx.dev";
|
|
6
|
+
var DEFAULT_AI_MODEL = "onyx";
|
|
5
7
|
var sanitizeBaseUrl = (u) => u.replace(/\/+$/, "");
|
|
6
8
|
|
|
7
9
|
// src/errors/config-error.ts
|
|
@@ -53,6 +55,8 @@ function readEnv(targetId) {
|
|
|
53
55
|
if (targetId && envId !== targetId) return {};
|
|
54
56
|
const res = dropUndefined({
|
|
55
57
|
baseUrl: pick("ONYX_DATABASE_BASE_URL"),
|
|
58
|
+
aiBaseUrl: pick("ONYX_AI_BASE_URL"),
|
|
59
|
+
defaultModel: pick("ONYX_DEFAULT_MODEL"),
|
|
56
60
|
databaseId: envId,
|
|
57
61
|
apiKey: pick("ONYX_DATABASE_API_KEY"),
|
|
58
62
|
apiSecret: pick("ONYX_DATABASE_API_SECRET")
|
|
@@ -71,11 +75,15 @@ async function resolveConfig(input) {
|
|
|
71
75
|
const env = readEnv(input?.databaseId);
|
|
72
76
|
const merged = {
|
|
73
77
|
baseUrl: DEFAULT_BASE_URL,
|
|
78
|
+
aiBaseUrl: DEFAULT_AI_BASE_URL,
|
|
79
|
+
defaultModel: DEFAULT_AI_MODEL,
|
|
74
80
|
...dropUndefined(env),
|
|
75
81
|
...dropUndefined(input)
|
|
76
82
|
};
|
|
77
83
|
dbg("merged (pre-validate):", mask(merged));
|
|
78
84
|
const baseUrl = sanitizeBaseUrl(merged.baseUrl ?? DEFAULT_BASE_URL);
|
|
85
|
+
const aiBaseUrl = sanitizeBaseUrl(merged.aiBaseUrl ?? DEFAULT_AI_BASE_URL);
|
|
86
|
+
const defaultModel = typeof merged.defaultModel === "string" && merged.defaultModel.trim() ? merged.defaultModel.trim() : DEFAULT_AI_MODEL;
|
|
79
87
|
const databaseId = merged.databaseId ?? "";
|
|
80
88
|
const apiKey = merged.apiKey ?? "";
|
|
81
89
|
const apiSecret = merged.apiSecret ?? "";
|
|
@@ -100,6 +108,8 @@ async function resolveConfig(input) {
|
|
|
100
108
|
}
|
|
101
109
|
const resolved = {
|
|
102
110
|
baseUrl,
|
|
111
|
+
aiBaseUrl,
|
|
112
|
+
defaultModel,
|
|
103
113
|
databaseId,
|
|
104
114
|
apiKey,
|
|
105
115
|
apiSecret,
|
|
@@ -1120,38 +1130,69 @@ var OnyxDatabaseImpl = class {
|
|
|
1120
1130
|
cfgPromise;
|
|
1121
1131
|
resolved = null;
|
|
1122
1132
|
http = null;
|
|
1133
|
+
aiHttp = null;
|
|
1123
1134
|
streams = /* @__PURE__ */ new Set();
|
|
1124
1135
|
requestLoggingEnabled;
|
|
1125
1136
|
responseLoggingEnabled;
|
|
1126
1137
|
defaultPartition;
|
|
1138
|
+
ai;
|
|
1127
1139
|
constructor(config, resolveConfigWithCache) {
|
|
1128
1140
|
this.requestLoggingEnabled = !!config?.requestLoggingEnabled;
|
|
1129
1141
|
this.responseLoggingEnabled = !!config?.responseLoggingEnabled;
|
|
1130
1142
|
this.defaultPartition = config?.partition;
|
|
1131
1143
|
this.cfgPromise = resolveConfigWithCache(config);
|
|
1144
|
+
this.ai = this.createAiFacade();
|
|
1132
1145
|
}
|
|
1133
|
-
async
|
|
1146
|
+
async resolveConfig() {
|
|
1134
1147
|
if (!this.resolved) {
|
|
1135
1148
|
this.resolved = await this.cfgPromise;
|
|
1136
1149
|
}
|
|
1150
|
+
return this.resolved;
|
|
1151
|
+
}
|
|
1152
|
+
async ensureClient() {
|
|
1153
|
+
const cfg = await this.resolveConfig();
|
|
1137
1154
|
if (!this.http) {
|
|
1138
1155
|
this.http = new HttpClient({
|
|
1139
|
-
baseUrl:
|
|
1140
|
-
apiKey:
|
|
1141
|
-
apiSecret:
|
|
1142
|
-
fetchImpl:
|
|
1156
|
+
baseUrl: cfg.baseUrl,
|
|
1157
|
+
apiKey: cfg.apiKey,
|
|
1158
|
+
apiSecret: cfg.apiSecret,
|
|
1159
|
+
fetchImpl: cfg.fetch,
|
|
1143
1160
|
requestLoggingEnabled: this.requestLoggingEnabled,
|
|
1144
1161
|
responseLoggingEnabled: this.responseLoggingEnabled,
|
|
1145
|
-
retryEnabled:
|
|
1146
|
-
maxRetries:
|
|
1147
|
-
retryInitialDelayMs:
|
|
1162
|
+
retryEnabled: cfg.retryEnabled,
|
|
1163
|
+
maxRetries: cfg.maxRetries,
|
|
1164
|
+
retryInitialDelayMs: cfg.retryInitialDelayMs
|
|
1148
1165
|
});
|
|
1149
1166
|
}
|
|
1150
1167
|
return {
|
|
1151
1168
|
http: this.http,
|
|
1152
|
-
fetchImpl:
|
|
1153
|
-
baseUrl:
|
|
1154
|
-
databaseId:
|
|
1169
|
+
fetchImpl: cfg.fetch,
|
|
1170
|
+
baseUrl: cfg.baseUrl,
|
|
1171
|
+
databaseId: cfg.databaseId,
|
|
1172
|
+
defaultModel: cfg.defaultModel ?? DEFAULT_AI_MODEL
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
async ensureAiClient() {
|
|
1176
|
+
const cfg = await this.resolveConfig();
|
|
1177
|
+
if (!this.aiHttp) {
|
|
1178
|
+
this.aiHttp = new HttpClient({
|
|
1179
|
+
baseUrl: cfg.aiBaseUrl,
|
|
1180
|
+
apiKey: cfg.apiKey,
|
|
1181
|
+
apiSecret: cfg.apiSecret,
|
|
1182
|
+
fetchImpl: cfg.fetch,
|
|
1183
|
+
requestLoggingEnabled: this.requestLoggingEnabled,
|
|
1184
|
+
responseLoggingEnabled: this.responseLoggingEnabled,
|
|
1185
|
+
retryEnabled: cfg.retryEnabled,
|
|
1186
|
+
maxRetries: cfg.maxRetries,
|
|
1187
|
+
retryInitialDelayMs: cfg.retryInitialDelayMs
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
return {
|
|
1191
|
+
http: this.aiHttp,
|
|
1192
|
+
fetchImpl: cfg.fetch,
|
|
1193
|
+
aiBaseUrl: cfg.aiBaseUrl,
|
|
1194
|
+
databaseId: cfg.databaseId,
|
|
1195
|
+
defaultModel: cfg.defaultModel ?? DEFAULT_AI_MODEL
|
|
1155
1196
|
};
|
|
1156
1197
|
}
|
|
1157
1198
|
registerStream(handle) {
|
|
@@ -1166,7 +1207,75 @@ var OnyxDatabaseImpl = class {
|
|
|
1166
1207
|
}
|
|
1167
1208
|
};
|
|
1168
1209
|
}
|
|
1210
|
+
createAiFacade() {
|
|
1211
|
+
const chat = ((contentOrRequest, options) => {
|
|
1212
|
+
if (typeof contentOrRequest === "string") {
|
|
1213
|
+
return this.chatWithContent(contentOrRequest, options);
|
|
1214
|
+
}
|
|
1215
|
+
return this.getAiChatClient().create(contentOrRequest, options);
|
|
1216
|
+
});
|
|
1217
|
+
return {
|
|
1218
|
+
chat,
|
|
1219
|
+
chatClient: () => this.getAiChatClient(),
|
|
1220
|
+
getModels: () => this.getModels(),
|
|
1221
|
+
getModel: (modelId) => this.getModel(modelId),
|
|
1222
|
+
requestScriptApproval: (input) => this.requestScriptApproval(input)
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
getRequestLoggingEnabled() {
|
|
1226
|
+
return this.requestLoggingEnabled;
|
|
1227
|
+
}
|
|
1228
|
+
getResponseLoggingEnabled() {
|
|
1229
|
+
return this.responseLoggingEnabled;
|
|
1230
|
+
}
|
|
1169
1231
|
/** -------- IOnyxDatabase -------- */
|
|
1232
|
+
getAiChatClient() {
|
|
1233
|
+
return new AiChatClientImpl(
|
|
1234
|
+
() => this.ensureAiClient(),
|
|
1235
|
+
(handle) => this.registerStream(handle),
|
|
1236
|
+
() => this.requestLoggingEnabled,
|
|
1237
|
+
() => this.responseLoggingEnabled
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
async chatWithContent(content, options) {
|
|
1241
|
+
const { defaultModel } = await this.ensureAiClient();
|
|
1242
|
+
const stream = options?.stream ?? false;
|
|
1243
|
+
const request = {
|
|
1244
|
+
model: options?.model ?? defaultModel,
|
|
1245
|
+
messages: [{ role: options?.role ?? "user", content }],
|
|
1246
|
+
stream
|
|
1247
|
+
};
|
|
1248
|
+
if (options && "temperature" in options) {
|
|
1249
|
+
request.temperature = options.temperature ?? null;
|
|
1250
|
+
}
|
|
1251
|
+
const result = await this.getAiChatClient().create(request, options);
|
|
1252
|
+
if (stream) return result;
|
|
1253
|
+
if (options?.raw) return result;
|
|
1254
|
+
const first = result.choices?.[0]?.message?.content;
|
|
1255
|
+
if (typeof first === "string" && first.trim().length > 0) {
|
|
1256
|
+
return first;
|
|
1257
|
+
}
|
|
1258
|
+
throw new Error("Chat completion response is missing message content");
|
|
1259
|
+
}
|
|
1260
|
+
chat(content, options) {
|
|
1261
|
+
if (typeof content === "string") {
|
|
1262
|
+
return this.chatWithContent(content, options);
|
|
1263
|
+
}
|
|
1264
|
+
return this.getAiChatClient();
|
|
1265
|
+
}
|
|
1266
|
+
async getModels() {
|
|
1267
|
+
const { http } = await this.ensureAiClient();
|
|
1268
|
+
return http.request("GET", "/v1/models");
|
|
1269
|
+
}
|
|
1270
|
+
async getModel(modelId) {
|
|
1271
|
+
const { http } = await this.ensureAiClient();
|
|
1272
|
+
const path = `/v1/models/${encodeURIComponent(modelId)}`;
|
|
1273
|
+
return http.request("GET", path);
|
|
1274
|
+
}
|
|
1275
|
+
async requestScriptApproval(input) {
|
|
1276
|
+
const { http } = await this.ensureAiClient();
|
|
1277
|
+
return http.request("POST", "/api/script-approvals", input);
|
|
1278
|
+
}
|
|
1170
1279
|
from(table) {
|
|
1171
1280
|
return new QueryBuilderImpl(this, String(table), this.defaultPartition);
|
|
1172
1281
|
}
|
|
@@ -1716,6 +1825,153 @@ var CascadeBuilderImpl = class {
|
|
|
1716
1825
|
return this.db.delete(table, primaryKey, opts);
|
|
1717
1826
|
}
|
|
1718
1827
|
};
|
|
1828
|
+
var AiChatClientImpl = class {
|
|
1829
|
+
constructor(resolveAiClient, registerStream, requestLoggingEnabled, responseLoggingEnabled) {
|
|
1830
|
+
this.resolveAiClient = resolveAiClient;
|
|
1831
|
+
this.registerStream = registerStream;
|
|
1832
|
+
this.requestLoggingEnabled = requestLoggingEnabled;
|
|
1833
|
+
this.responseLoggingEnabled = responseLoggingEnabled;
|
|
1834
|
+
}
|
|
1835
|
+
normalizeEventData(rawEvent) {
|
|
1836
|
+
const lines = rawEvent.split("\n");
|
|
1837
|
+
const dataLines = [];
|
|
1838
|
+
for (const line of lines) {
|
|
1839
|
+
const trimmed = line.trim();
|
|
1840
|
+
if (!trimmed || trimmed.startsWith(":")) continue;
|
|
1841
|
+
if (trimmed.startsWith("data:")) {
|
|
1842
|
+
dataLines.push(trimmed.slice(5).trim());
|
|
1843
|
+
} else {
|
|
1844
|
+
dataLines.push(trimmed);
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
if (!dataLines.length) return null;
|
|
1848
|
+
const joined = dataLines.join("\n").trim();
|
|
1849
|
+
return joined.length > 0 ? joined : null;
|
|
1850
|
+
}
|
|
1851
|
+
logRequest(url, body, headers) {
|
|
1852
|
+
if (!this.requestLoggingEnabled()) return;
|
|
1853
|
+
console.log(`POST ${url}`);
|
|
1854
|
+
if (body != null) {
|
|
1855
|
+
const serialized = typeof body === "string" ? body : JSON.stringify(body);
|
|
1856
|
+
console.log(serialized);
|
|
1857
|
+
}
|
|
1858
|
+
const headerLog = { ...headers };
|
|
1859
|
+
if (headerLog["x-onyx-secret"]) headerLog["x-onyx-secret"] = "[REDACTED]";
|
|
1860
|
+
console.log("Headers:", headerLog);
|
|
1861
|
+
}
|
|
1862
|
+
logResponse(status, statusText, raw) {
|
|
1863
|
+
if (!this.responseLoggingEnabled()) return;
|
|
1864
|
+
const statusLine = `${status} ${statusText}`.trim();
|
|
1865
|
+
console.log(statusLine);
|
|
1866
|
+
if (raw && raw.trim().length > 0) {
|
|
1867
|
+
console.log(raw);
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
toOnyxError(status, statusText, raw) {
|
|
1871
|
+
let parsed = raw;
|
|
1872
|
+
try {
|
|
1873
|
+
parsed = parseJsonAllowNaN(raw);
|
|
1874
|
+
} catch {
|
|
1875
|
+
}
|
|
1876
|
+
const message = typeof parsed === "object" && parsed !== null && "error" in parsed && typeof parsed.error === "object" && typeof parsed.error?.message === "string" ? String(parsed.error.message) : `${status} ${statusText}`;
|
|
1877
|
+
return new OnyxHttpError(message, status, statusText, parsed, raw);
|
|
1878
|
+
}
|
|
1879
|
+
async create(request, options) {
|
|
1880
|
+
const body = { ...request, stream: !!request.stream };
|
|
1881
|
+
const { http, fetchImpl, aiBaseUrl, databaseId } = await this.resolveAiClient();
|
|
1882
|
+
const params = new URLSearchParams();
|
|
1883
|
+
const scopedDb = options?.databaseId ?? databaseId;
|
|
1884
|
+
if (scopedDb) params.append("databaseId", scopedDb);
|
|
1885
|
+
const path = `/v1/chat/completions${params.size ? `?${params.toString()}` : ""}`;
|
|
1886
|
+
if (!body.stream) {
|
|
1887
|
+
return http.request("POST", path, body);
|
|
1888
|
+
}
|
|
1889
|
+
const url = `${aiBaseUrl}${path}`;
|
|
1890
|
+
const headers = http.headers({ Accept: "text/event-stream" });
|
|
1891
|
+
this.logRequest(url, body, headers);
|
|
1892
|
+
const res = await fetchImpl(url, {
|
|
1893
|
+
method: "POST",
|
|
1894
|
+
headers,
|
|
1895
|
+
body: JSON.stringify(body)
|
|
1896
|
+
});
|
|
1897
|
+
if (!res.ok) {
|
|
1898
|
+
const raw = await res.text();
|
|
1899
|
+
this.logResponse(res.status, res.statusText, raw);
|
|
1900
|
+
throw this.toOnyxError(res.status, res.statusText, raw);
|
|
1901
|
+
}
|
|
1902
|
+
this.logResponse(res.status, res.statusText);
|
|
1903
|
+
const bodyStream = res.body;
|
|
1904
|
+
const reader = bodyStream && typeof bodyStream.getReader === "function" ? bodyStream.getReader() : null;
|
|
1905
|
+
if (!reader) {
|
|
1906
|
+
throw new OnyxHttpError(
|
|
1907
|
+
"Streaming response body is not readable",
|
|
1908
|
+
res.status,
|
|
1909
|
+
res.statusText,
|
|
1910
|
+
null,
|
|
1911
|
+
""
|
|
1912
|
+
);
|
|
1913
|
+
}
|
|
1914
|
+
let canceled = false;
|
|
1915
|
+
const handle = {
|
|
1916
|
+
cancel: () => {
|
|
1917
|
+
if (canceled) return;
|
|
1918
|
+
canceled = true;
|
|
1919
|
+
try {
|
|
1920
|
+
reader.cancel?.();
|
|
1921
|
+
} catch {
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
const registered = this.registerStream(handle);
|
|
1926
|
+
const normalizeEvent = (rawEvent) => this.normalizeEventData(rawEvent);
|
|
1927
|
+
const stream = {
|
|
1928
|
+
async *[Symbol.asyncIterator]() {
|
|
1929
|
+
const decoder = new TextDecoder("utf-8");
|
|
1930
|
+
let buffer = "";
|
|
1931
|
+
try {
|
|
1932
|
+
while (!canceled) {
|
|
1933
|
+
const { done, value } = await reader.read();
|
|
1934
|
+
if (done) break;
|
|
1935
|
+
if (value) {
|
|
1936
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1937
|
+
}
|
|
1938
|
+
let splitIndex = buffer.indexOf("\n\n");
|
|
1939
|
+
while (splitIndex !== -1) {
|
|
1940
|
+
const rawEvent = buffer.slice(0, splitIndex);
|
|
1941
|
+
buffer = buffer.slice(splitIndex + 2);
|
|
1942
|
+
const data = normalizeEvent(rawEvent);
|
|
1943
|
+
if (data === "[DONE]") return;
|
|
1944
|
+
if (data) {
|
|
1945
|
+
try {
|
|
1946
|
+
yield parseJsonAllowNaN(data);
|
|
1947
|
+
} catch {
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
splitIndex = buffer.indexOf("\n\n");
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
buffer += decoder.decode();
|
|
1954
|
+
const remaining = buffer.trim();
|
|
1955
|
+
if (remaining && remaining !== "[DONE]") {
|
|
1956
|
+
const data = normalizeEvent(remaining);
|
|
1957
|
+
if (data && data !== "[DONE]") {
|
|
1958
|
+
try {
|
|
1959
|
+
yield parseJsonAllowNaN(data);
|
|
1960
|
+
} catch {
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
} finally {
|
|
1965
|
+
registered.cancel();
|
|
1966
|
+
}
|
|
1967
|
+
},
|
|
1968
|
+
cancel() {
|
|
1969
|
+
registered.cancel();
|
|
1970
|
+
}
|
|
1971
|
+
};
|
|
1972
|
+
return stream;
|
|
1973
|
+
}
|
|
1974
|
+
};
|
|
1719
1975
|
function createOnyxFacade(resolveConfig2) {
|
|
1720
1976
|
let cachedCfg = null;
|
|
1721
1977
|
function resolveConfigWithCache(config) {
|