@promptbook/cli 0.103.0-46 → 0.103.0-48
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/apps/agents-server/TODO.txt +2 -2
- package/apps/agents-server/config.ts.todo +5 -279
- package/apps/agents-server/next.config.ts +3 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +1 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/book/test.http +2 -2
- package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +13 -5
- package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/TODO.txt +1 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/route.ts +53 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/systemMessage/route.ts +45 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/profile/route.ts +54 -0
- package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +84 -18
- package/apps/agents-server/src/app/agents/[agentName]/book/page.tsx +9 -5
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/{SelfLearningBook.tsx → AgentBookAndChatComponent.tsx} +5 -48
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/page.tsx +7 -4
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatWrapper.tsx +38 -0
- package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +23 -0
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +8 -6
- package/apps/agents-server/src/app/agents/page.tsx +11 -0
- package/apps/agents-server/src/app/api/chat/route.ts +1 -1
- package/apps/agents-server/src/app/api/chat-streaming/route.ts +5 -1
- package/apps/agents-server/src/app/api/upload/route.ts +71 -0
- package/apps/agents-server/src/{supabase/getSupabase.ts → database/$provideSupabase.ts} +11 -7
- package/apps/agents-server/src/{supabase/getSupabaseForBrowser.ts → database/$provideSupabaseForBrowser.ts} +9 -5
- package/apps/agents-server/src/{supabase/getSupabaseForServer.ts → database/$provideSupabaseForServer.ts} +4 -4
- package/apps/agents-server/src/{supabase/getSupabaseForWorker.ts → database/$provideSupabaseForWorker.ts} +5 -4
- package/apps/agents-server/src/database/schema.sql +131 -0
- package/apps/agents-server/src/database/schema.ts +217 -0
- package/apps/agents-server/src/tools/$provideAgentCollectionForServer.ts +3 -2
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +28 -0
- package/apps/agents-server/src/tools/$provideOpenAiAssistantExecutionToolsForServer.ts +1 -1
- package/apps/agents-server/src/utils/cdn/classes/DigitalOceanSpaces.ts +119 -0
- package/apps/agents-server/src/utils/cdn/interfaces/IFilesStorage.ts +32 -0
- package/apps/agents-server/src/utils/cdn/interfaces/IStorage.ts +14 -0
- package/apps/agents-server/src/utils/cdn/utils/getUserFileCdnKey.ts +28 -0
- package/apps/agents-server/src/utils/cdn/utils/nameToSubfolderPath.ts +9 -0
- package/apps/agents-server/src/utils/cdn/utils/nextRequestToNodeRequest.ts +27 -0
- package/apps/agents-server/src/utils/validators/validateMimeType.ts +24 -0
- package/apps/agents-server/tsconfig.json +1 -1
- package/esm/index.es.js +319 -181
- package/esm/index.es.js.map +1 -1
- package/esm/typings/servers.d.ts +1 -7
- package/esm/typings/src/_packages/components.index.d.ts +4 -0
- package/esm/typings/src/_packages/core.index.d.ts +22 -14
- package/esm/typings/src/_packages/types.index.d.ts +14 -6
- package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +7 -3
- package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +6 -1
- package/esm/typings/src/book-2.0/agent-source/AgentSourceParseResult.d.ts +3 -2
- package/esm/typings/src/book-2.0/agent-source/computeAgentHash.d.ts +8 -0
- package/esm/typings/src/book-2.0/agent-source/computeAgentHash.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/agent-source/createCommitmentRegex.d.ts +1 -1
- package/esm/typings/src/book-2.0/agent-source/createDefaultAgentName.d.ts +8 -0
- package/esm/typings/src/book-2.0/agent-source/normalizeAgentName.d.ts +9 -0
- package/esm/typings/src/book-2.0/agent-source/normalizeAgentName.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/agent-source/parseAgentSourceWithCommitments.d.ts +1 -1
- package/esm/typings/src/book-components/Chat/AgentChat/AgentChat.d.ts +14 -0
- package/esm/typings/src/book-components/Chat/AgentChat/AgentChat.test.d.ts +1 -0
- package/esm/typings/src/book-components/Chat/AgentChat/AgentChatProps.d.ts +13 -0
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +1 -60
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +57 -32
- package/esm/typings/src/{book-2.0/commitments → commitments}/ACTION/ACTION.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/DELETE/DELETE.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/FORMAT/FORMAT.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/GOAL/GOAL.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/KNOWLEDGE/KNOWLEDGE.d.ts +1 -5
- package/esm/typings/src/{book-2.0/commitments → commitments}/MEMORY/MEMORY.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/MESSAGE/MESSAGE.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/META/META.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/META_IMAGE/META_IMAGE.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/META_LINK/META_LINK.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/MODEL/MODEL.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/NOTE/NOTE.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/PERSONA/PERSONA.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/RULE/RULE.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/SAMPLE/SAMPLE.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/SCENARIO/SCENARIO.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/STYLE/STYLE.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/_base/BaseCommitmentDefinition.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/_base/CommitmentDefinition.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/_base/NotYetImplementedCommitmentDefinition.d.ts +1 -1
- package/esm/typings/src/{book-2.0/commitments → commitments}/_base/createEmptyAgentModelRequirements.d.ts +1 -1
- package/esm/typings/src/execution/LlmExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/utils/assertUniqueModels.d.ts +12 -0
- package/esm/typings/src/llm-providers/agent/Agent.d.ts +10 -9
- package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +5 -1
- package/esm/typings/src/llm-providers/agent/CreateAgentLlmExecutionToolsOptions.d.ts +1 -1
- package/esm/typings/src/llm-providers/agent/RemoteAgent.d.ts +32 -0
- package/esm/typings/src/llm-providers/agent/RemoteAgentOptions.d.ts +11 -0
- package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +29 -4
- package/esm/typings/src/llm-providers/openai/openai-models.test.d.ts +4 -0
- package/esm/typings/src/remote-server/startAgentServer.d.ts +1 -1
- package/esm/typings/src/remote-server/startRemoteServer.d.ts +1 -2
- package/esm/typings/src/storage/_common/PromptbookStorage.d.ts +1 -0
- package/esm/typings/src/transpilers/openai-sdk/register.d.ts +1 -1
- package/esm/typings/src/types/typeAliases.d.ts +12 -0
- package/esm/typings/src/utils/color/internal-utils/checkChannelValue.d.ts +0 -3
- package/esm/typings/src/utils/normalization/normalize-to-kebab-case.d.ts +2 -0
- package/esm/typings/src/utils/normalization/normalizeTo_PascalCase.d.ts +3 -0
- package/esm/typings/src/utils/normalization/normalizeTo_camelCase.d.ts +2 -0
- package/esm/typings/src/utils/normalization/titleToName.d.ts +2 -0
- package/esm/typings/src/utils/random/$generateBookBoilerplate.d.ts +2 -2
- package/esm/typings/src/utils/random/$randomFullnameWithColor.d.ts +1 -1
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +320 -182
- package/umd/index.umd.js.map +1 -1
- package/apps/agents-server/src/supabase/TODO.txt +0 -1
- /package/esm/typings/src/{book-2.0/commitments → commitments}/_base/BookCommitment.d.ts +0 -0
- /package/esm/typings/src/{book-2.0/commitments → commitments}/_base/ParsedCommitment.d.ts +0 -0
- /package/esm/typings/src/{book-2.0/commitments → commitments}/index.d.ts +0 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
|
|
2
|
+
-- Note: This is primary source of truth for the database schema
|
|
3
|
+
-- In future we want to be compatible with more then Supabase so we keep SQL as main schema definition
|
|
4
|
+
-- To update, search for [💽]
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
CREATE TABLE IF NOT EXISTS "EnvironmentVariable" (
|
|
9
|
+
"id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
10
|
+
"key" TEXT NOT NULL,
|
|
11
|
+
"value" TEXT NOT NULL,
|
|
12
|
+
"note" TEXT NULL,
|
|
13
|
+
CONSTRAINT EnvironmentVariable_key_key UNIQUE ("key")
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
CREATE TABLE IF NOT EXISTS "Agent" (
|
|
18
|
+
"id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
19
|
+
"agentName" TEXT NOT NULL,
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
23
|
+
"updatedAt" TIMESTAMP WITH TIME ZONE NULL DEFAULT NULL,
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
"agentHash" TEXT NOT NULL,
|
|
27
|
+
"agentSource" TEXT NOT NULL,
|
|
28
|
+
"agentProfile" JSONB NOT NULL,
|
|
29
|
+
"promptbookEngineVersion" TEXT NOT NULL,
|
|
30
|
+
|
|
31
|
+
"usage" JSONB NULL,
|
|
32
|
+
"preparedModelRequirements" JSONB NULL,
|
|
33
|
+
"preparedExternals" JSONB NULL
|
|
34
|
+
);
|
|
35
|
+
-- Ensure uniqueness of agentName even on repeated schema application without duplicate constraint creation
|
|
36
|
+
CREATE UNIQUE INDEX IF NOT EXISTS agent_agentname_key ON "Agent" ("agentName");
|
|
37
|
+
COMMENT ON COLUMN "Agent"."agentName" IS 'The unique name of the agent derived from the first line of the `agentSource`, automatically updated on `agentSource` change';
|
|
38
|
+
COMMENT ON COLUMN "Agent"."agentHash" IS 'The hash of the `agentSource`, automatically updated on `agentSource` change';
|
|
39
|
+
COMMENT ON COLUMN "Agent"."agentSource" IS 'The source code of the agent';
|
|
40
|
+
COMMENT ON COLUMN "Agent"."agentProfile" IS 'The profile of the agent generated from the `agentSource`, automatically updated on `agentSource` change <- TODO: [🕛]';
|
|
41
|
+
COMMENT ON COLUMN "Agent"."promptbookEngineVersion" IS 'The version of the Promptbook engine used for last update of the agent';
|
|
42
|
+
COMMENT ON COLUMN "Agent"."usage" IS 'Usage and spending statistics for the agent';
|
|
43
|
+
COMMENT ON COLUMN "Agent"."preparedModelRequirements" IS 'The prepared model requirements for the agent, generated from the `agentSource` but not after every change (only on explicit request), there is `agentHash` to identify the version of the `agentSource` this was prepared from';
|
|
44
|
+
COMMENT ON COLUMN "Agent"."preparedExternals" IS 'The prepared externals for the agent, generated from the `agentSource` but not after every change (only on explicit request), there is `agentHash` to identify the version of the `agentSource` this was prepared from';
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
CREATE TABLE IF NOT EXISTS "AgentHistory" (
|
|
48
|
+
"id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
49
|
+
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
50
|
+
|
|
51
|
+
"agentName" TEXT NOT NULL,
|
|
52
|
+
"agentHash" TEXT NOT NULL,
|
|
53
|
+
"previousAgentHash" TEXT NULL,
|
|
54
|
+
"agentSource" TEXT NOT NULL,
|
|
55
|
+
"promptbookEngineVersion" TEXT NOT NULL
|
|
56
|
+
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
CREATE INDEX IF NOT EXISTS "AgentHistory_agentName_idx" ON "AgentHistory" ("agentName");
|
|
60
|
+
CREATE INDEX IF NOT EXISTS "AgentHistory_agentHash_idx" ON "AgentHistory" ("agentHash");
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
CREATE TABLE IF NOT EXISTS "ChatHistory" (
|
|
64
|
+
"id" BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
|
65
|
+
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
66
|
+
|
|
67
|
+
"messageHash" TEXT NOT NULL,
|
|
68
|
+
"previousMessageHash" TEXT NULL,
|
|
69
|
+
"agentName" TEXT NOT NULL,
|
|
70
|
+
"agentHash" TEXT NOT NULL,
|
|
71
|
+
"message" JSONB NOT NULL,
|
|
72
|
+
|
|
73
|
+
-- Telemetry:
|
|
74
|
+
"promptbookEngineVersion" TEXT NULL,
|
|
75
|
+
"url" TEXT NULL,
|
|
76
|
+
"ip" TEXT NULL,
|
|
77
|
+
"userAgent" TEXT NULL,
|
|
78
|
+
"language" TEXT NULL,
|
|
79
|
+
"platform" TEXT NULL
|
|
80
|
+
);
|
|
81
|
+
COMMENT ON COLUMN "ChatHistory"."url" IS 'The URL where the chat was happening';
|
|
82
|
+
COMMENT ON COLUMN "ChatHistory"."ip" IS 'The IP address of the user';
|
|
83
|
+
COMMENT ON COLUMN "ChatHistory"."userAgent" IS 'The user agent (browser) of the user';
|
|
84
|
+
COMMENT ON COLUMN "ChatHistory"."language" IS 'The language (from the browser) of the user';
|
|
85
|
+
COMMENT ON COLUMN "ChatHistory"."platform" IS 'The platform of the user';
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
CREATE TABLE IF NOT EXISTS "ChatFeedback" (
|
|
89
|
+
"id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
90
|
+
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
91
|
+
|
|
92
|
+
"agentName" TEXT NOT NULL,
|
|
93
|
+
"agentHash" TEXT NOT NULL,
|
|
94
|
+
"rating" TEXT NULL,
|
|
95
|
+
"textRating" TEXT NULL,
|
|
96
|
+
"chatThread" TEXT NULL,
|
|
97
|
+
"userNote" TEXT NULL,
|
|
98
|
+
"expectedAnswer" TEXT NULL,
|
|
99
|
+
|
|
100
|
+
-- Telemetry:
|
|
101
|
+
"promptbookEngineVersion" TEXT NULL,
|
|
102
|
+
"url" TEXT NULL,
|
|
103
|
+
"ip" TEXT NULL,
|
|
104
|
+
"userAgent" TEXT NULL,
|
|
105
|
+
"language" TEXT NULL,
|
|
106
|
+
"platform" TEXT NULL
|
|
107
|
+
);
|
|
108
|
+
COMMENT ON COLUMN "ChatFeedback"."url" IS 'The URL where the chat was happening';
|
|
109
|
+
COMMENT ON COLUMN "ChatFeedback"."ip" IS 'The IP address of the user';
|
|
110
|
+
COMMENT ON COLUMN "ChatFeedback"."userAgent" IS 'The user agent (browser) of the user';
|
|
111
|
+
COMMENT ON COLUMN "ChatFeedback"."language" IS 'The language (from the browser) of the user';
|
|
112
|
+
COMMENT ON COLUMN "ChatFeedback"."platform" IS 'The platform of the user';
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
/*
|
|
116
|
+
CREATE TABLE IF NOT EXISTS "AgentActionHistory" (
|
|
117
|
+
id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
|
118
|
+
createdAt TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
|
119
|
+
|
|
120
|
+
);
|
|
121
|
+
*/
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
/*
|
|
125
|
+
CREATE TABLE IF NOT EXISTS "Xxx" (
|
|
126
|
+
id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
|
127
|
+
);
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
-- TODO: !!!! Create propper database migrations
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUTO-GENERATED TYPES FROM `schema.sql`
|
|
3
|
+
* Source of truth: `schema.sql` *(do not edit table structure here manually)*
|
|
4
|
+
*
|
|
5
|
+
* [💽] Prompt:
|
|
6
|
+
* Re-generate supabase typescript schema from the `./schema.sql`
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Json helper (Supabase style)
|
|
10
|
+
export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[];
|
|
11
|
+
|
|
12
|
+
// Public schema database interface (Supabase convention)
|
|
13
|
+
export type AgentsServerDatabase = {
|
|
14
|
+
public: {
|
|
15
|
+
Tables: {
|
|
16
|
+
EnvironmentVariable: {
|
|
17
|
+
Row: {
|
|
18
|
+
id: number;
|
|
19
|
+
key: string;
|
|
20
|
+
value: string;
|
|
21
|
+
note: string | null;
|
|
22
|
+
};
|
|
23
|
+
Insert: {
|
|
24
|
+
id?: number;
|
|
25
|
+
key: string;
|
|
26
|
+
value: string;
|
|
27
|
+
note?: string | null;
|
|
28
|
+
};
|
|
29
|
+
Update: {
|
|
30
|
+
id?: number;
|
|
31
|
+
key?: string;
|
|
32
|
+
value?: string;
|
|
33
|
+
note?: string | null;
|
|
34
|
+
};
|
|
35
|
+
Relationships: [];
|
|
36
|
+
};
|
|
37
|
+
Agent: {
|
|
38
|
+
Row: {
|
|
39
|
+
id: number;
|
|
40
|
+
agentName: string;
|
|
41
|
+
createdAt: string;
|
|
42
|
+
updatedAt: string | null;
|
|
43
|
+
agentHash: string;
|
|
44
|
+
agentSource: string;
|
|
45
|
+
agentProfile: Json;
|
|
46
|
+
promptbookEngineVersion: string;
|
|
47
|
+
usage: Json | null;
|
|
48
|
+
preparedModelRequirements: Json | null;
|
|
49
|
+
preparedExternals: Json | null;
|
|
50
|
+
};
|
|
51
|
+
Insert: {
|
|
52
|
+
id?: number;
|
|
53
|
+
agentName: string;
|
|
54
|
+
createdAt: string;
|
|
55
|
+
updatedAt?: string | null;
|
|
56
|
+
agentHash: string;
|
|
57
|
+
agentSource: string;
|
|
58
|
+
agentProfile: Json;
|
|
59
|
+
promptbookEngineVersion: string;
|
|
60
|
+
usage?: Json | null;
|
|
61
|
+
preparedModelRequirements?: Json | null;
|
|
62
|
+
preparedExternals?: Json | null;
|
|
63
|
+
};
|
|
64
|
+
Update: {
|
|
65
|
+
id?: number;
|
|
66
|
+
agentName?: string;
|
|
67
|
+
createdAt?: string;
|
|
68
|
+
updatedAt?: string | null;
|
|
69
|
+
agentHash?: string;
|
|
70
|
+
agentSource?: string;
|
|
71
|
+
agentProfile?: Json;
|
|
72
|
+
promptbookEngineVersion?: string;
|
|
73
|
+
usage?: Json | null;
|
|
74
|
+
preparedModelRequirements?: Json | null;
|
|
75
|
+
preparedExternals?: Json | null;
|
|
76
|
+
};
|
|
77
|
+
Relationships: [];
|
|
78
|
+
};
|
|
79
|
+
AgentHistory: {
|
|
80
|
+
Row: {
|
|
81
|
+
id: number;
|
|
82
|
+
createdAt: string;
|
|
83
|
+
agentName: string;
|
|
84
|
+
agentHash: string;
|
|
85
|
+
previousAgentHash: string | null;
|
|
86
|
+
agentSource: string;
|
|
87
|
+
promptbookEngineVersion: string;
|
|
88
|
+
};
|
|
89
|
+
Insert: {
|
|
90
|
+
id?: number;
|
|
91
|
+
createdAt: string;
|
|
92
|
+
agentName: string;
|
|
93
|
+
agentHash: string;
|
|
94
|
+
previousAgentHash?: string | null;
|
|
95
|
+
agentSource: string;
|
|
96
|
+
promptbookEngineVersion: string;
|
|
97
|
+
};
|
|
98
|
+
Update: {
|
|
99
|
+
id?: number;
|
|
100
|
+
createdAt?: string;
|
|
101
|
+
agentName?: string;
|
|
102
|
+
agentHash?: string;
|
|
103
|
+
previousAgentHash?: string | null;
|
|
104
|
+
agentSource?: string;
|
|
105
|
+
promptbookEngineVersion?: string;
|
|
106
|
+
};
|
|
107
|
+
Relationships: [];
|
|
108
|
+
};
|
|
109
|
+
ChatHistory: {
|
|
110
|
+
Row: {
|
|
111
|
+
id: number;
|
|
112
|
+
createdAt: string;
|
|
113
|
+
messageHash: string;
|
|
114
|
+
previousMessageHash: string | null;
|
|
115
|
+
agentName: string;
|
|
116
|
+
agentHash: string;
|
|
117
|
+
message: Json;
|
|
118
|
+
promptbookEngineVersion: string | null;
|
|
119
|
+
url: string | null;
|
|
120
|
+
ip: string | null;
|
|
121
|
+
userAgent: string | null;
|
|
122
|
+
language: string | null;
|
|
123
|
+
platform: string | null;
|
|
124
|
+
};
|
|
125
|
+
Insert: {
|
|
126
|
+
id?: number;
|
|
127
|
+
createdAt: string;
|
|
128
|
+
messageHash: string;
|
|
129
|
+
previousMessageHash?: string | null;
|
|
130
|
+
agentName: string;
|
|
131
|
+
agentHash: string;
|
|
132
|
+
message: Json;
|
|
133
|
+
promptbookEngineVersion?: string | null;
|
|
134
|
+
url?: string | null;
|
|
135
|
+
ip?: string | null;
|
|
136
|
+
userAgent?: string | null;
|
|
137
|
+
language?: string | null;
|
|
138
|
+
platform?: string | null;
|
|
139
|
+
};
|
|
140
|
+
Update: {
|
|
141
|
+
id?: number;
|
|
142
|
+
createdAt?: string;
|
|
143
|
+
messageHash?: string;
|
|
144
|
+
previousMessageHash?: string | null;
|
|
145
|
+
agentName?: string;
|
|
146
|
+
agentHash?: string;
|
|
147
|
+
message?: Json;
|
|
148
|
+
promptbookEngineVersion?: string | null;
|
|
149
|
+
url?: string | null;
|
|
150
|
+
ip?: string | null;
|
|
151
|
+
userAgent?: string | null;
|
|
152
|
+
language?: string | null;
|
|
153
|
+
platform?: string | null;
|
|
154
|
+
};
|
|
155
|
+
Relationships: [];
|
|
156
|
+
};
|
|
157
|
+
ChatFeedback: {
|
|
158
|
+
Row: {
|
|
159
|
+
id: number;
|
|
160
|
+
createdAt: string;
|
|
161
|
+
agentName: string;
|
|
162
|
+
agentHash: string;
|
|
163
|
+
rating: string | null;
|
|
164
|
+
textRating: string | null;
|
|
165
|
+
chatThread: string | null;
|
|
166
|
+
userNote: string | null;
|
|
167
|
+
expectedAnswer: string | null;
|
|
168
|
+
promptbookEngineVersion: string | null;
|
|
169
|
+
url: string | null;
|
|
170
|
+
ip: string | null;
|
|
171
|
+
userAgent: string | null;
|
|
172
|
+
language: string | null;
|
|
173
|
+
platform: string | null;
|
|
174
|
+
};
|
|
175
|
+
Insert: {
|
|
176
|
+
id?: number;
|
|
177
|
+
createdAt: string;
|
|
178
|
+
agentName: string;
|
|
179
|
+
agentHash: string;
|
|
180
|
+
rating?: string | null;
|
|
181
|
+
textRating?: string | null;
|
|
182
|
+
chatThread?: string | null;
|
|
183
|
+
userNote?: string | null;
|
|
184
|
+
expectedAnswer?: string | null;
|
|
185
|
+
promptbookEngineVersion?: string | null;
|
|
186
|
+
url?: string | null;
|
|
187
|
+
ip?: string | null;
|
|
188
|
+
userAgent?: string | null;
|
|
189
|
+
language?: string | null;
|
|
190
|
+
platform?: string | null;
|
|
191
|
+
};
|
|
192
|
+
Update: {
|
|
193
|
+
id?: number;
|
|
194
|
+
createdAt?: string;
|
|
195
|
+
agentName?: string;
|
|
196
|
+
agentHash?: string;
|
|
197
|
+
rating?: string | null;
|
|
198
|
+
textRating?: string | null;
|
|
199
|
+
chatThread?: string | null;
|
|
200
|
+
userNote?: string | null;
|
|
201
|
+
expectedAnswer?: string | null;
|
|
202
|
+
promptbookEngineVersion?: string | null;
|
|
203
|
+
url?: string | null;
|
|
204
|
+
ip?: string | null;
|
|
205
|
+
userAgent?: string | null;
|
|
206
|
+
language?: string | null;
|
|
207
|
+
platform?: string | null;
|
|
208
|
+
};
|
|
209
|
+
Relationships: [];
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
Views: Record<string, never>;
|
|
213
|
+
Functions: Record<string, never>;
|
|
214
|
+
Enums: Record<string, never>;
|
|
215
|
+
CompositeTypes: Record<string, never>;
|
|
216
|
+
};
|
|
217
|
+
};
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { AgentCollectionInSupabase } from '@promptbook-local/core';
|
|
4
4
|
import { AgentCollection } from '@promptbook-local/types';
|
|
5
|
-
import {
|
|
5
|
+
import { $provideSupabaseForServer } from '../database/$provideSupabaseForServer';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Cache of provided agent collection
|
|
9
|
+
*
|
|
9
10
|
* @private internal cache for `$provideAgentCollectionForServer`
|
|
10
11
|
*/
|
|
11
12
|
let agentCollection: null | AgentCollection = null;
|
|
@@ -39,7 +40,7 @@ export async function $provideAgentCollectionForServer(): Promise<AgentCollectio
|
|
|
39
40
|
});
|
|
40
41
|
*/
|
|
41
42
|
|
|
42
|
-
const supabase =
|
|
43
|
+
const supabase = $provideSupabaseForServer();
|
|
43
44
|
|
|
44
45
|
agentCollection = new AgentCollectionInSupabase(supabase, {
|
|
45
46
|
isVerbose,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DigitalOceanSpaces } from '../utils/cdn/classes/DigitalOceanSpaces';
|
|
2
|
+
import { IIFilesStorageWithCdn } from '../utils/cdn/interfaces/IFilesStorage';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Cache of CDN instance
|
|
6
|
+
*
|
|
7
|
+
* @private internal cache for `$provideCdnForServer`
|
|
8
|
+
*/
|
|
9
|
+
let cdn: IIFilesStorageWithCdn | null = null;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* !!!
|
|
13
|
+
*/
|
|
14
|
+
export function $provideCdnForServer(): IIFilesStorageWithCdn {
|
|
15
|
+
if (!cdn) {
|
|
16
|
+
cdn = new DigitalOceanSpaces({
|
|
17
|
+
bucket: process.env.CDN_BUCKET!,
|
|
18
|
+
pathPrefix: process.env.NEXT_PUBLIC_CDN_PATH_PREFIX!,
|
|
19
|
+
endpoint: process.env.CDN_ENDPOINT!,
|
|
20
|
+
accessKeyId: process.env.CDN_ACCESS_KEY_ID!,
|
|
21
|
+
secretAccessKey: process.env.CDN_SECRET_ACCESS_KEY!,
|
|
22
|
+
cdnPublicUrl: new URL(process.env.NEXT_PUBLIC_CDN_PUBLIC_URL!),
|
|
23
|
+
gzip: true,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return cdn;
|
|
28
|
+
}
|
|
@@ -26,7 +26,7 @@ export async function $provideOpenAiAssistantExecutionToolsForServer(): Promise<
|
|
|
26
26
|
|
|
27
27
|
executionTools = new OpenAiAssistantExecutionTools({
|
|
28
28
|
apiKey: process.env.OPENAI_API_KEY,
|
|
29
|
-
assistantId: '!!!!
|
|
29
|
+
assistantId: 'abstract_assistant', // <- TODO: !!!! In `OpenAiAssistantExecutionTools` Allow to create abstract assistants with `isCreatingNewAssistantsAllowed`
|
|
30
30
|
isCreatingNewAssistantsAllowed: true,
|
|
31
31
|
isVerbose,
|
|
32
32
|
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { GetObjectCommand, PutObjectCommand, PutObjectCommandInput, S3Client } from '@aws-sdk/client-s3';
|
|
2
|
+
import { NotYetImplementedError } from '@promptbook-local/core';
|
|
3
|
+
import { gzip, ungzip } from 'node-gzip';
|
|
4
|
+
import { TODO_USE } from '../../../../../../src/utils/organization/TODO_USE';
|
|
5
|
+
import { validateMimeType } from '../../validators/validateMimeType';
|
|
6
|
+
import type { IFile, IIFilesStorageWithCdn } from '../interfaces/IFilesStorage';
|
|
7
|
+
|
|
8
|
+
type IDigitalOceanSpacesConfig = {
|
|
9
|
+
readonly bucket: string;
|
|
10
|
+
readonly pathPrefix: string;
|
|
11
|
+
readonly endpoint: string;
|
|
12
|
+
readonly accessKeyId: string;
|
|
13
|
+
readonly secretAccessKey: string;
|
|
14
|
+
readonly cdnPublicUrl: URL;
|
|
15
|
+
readonly gzip: boolean;
|
|
16
|
+
|
|
17
|
+
// TODO: [⛳️] Probbably prefix should be in this config not on the consumer side
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export class DigitalOceanSpaces implements IIFilesStorageWithCdn {
|
|
21
|
+
public get cdnPublicUrl() {
|
|
22
|
+
return this.config.cdnPublicUrl;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private s3: S3Client;
|
|
26
|
+
|
|
27
|
+
public constructor(private readonly config: IDigitalOceanSpacesConfig) {
|
|
28
|
+
this.s3 = new S3Client({
|
|
29
|
+
region: 'auto',
|
|
30
|
+
endpoint: 'https://' + config.endpoint,
|
|
31
|
+
credentials: {
|
|
32
|
+
accessKeyId: config.accessKeyId,
|
|
33
|
+
secretAccessKey: config.secretAccessKey,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public getItemUrl(key: string): URL {
|
|
39
|
+
return new URL(this.config.pathPrefix + '/' + key, this.cdnPublicUrl);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public async getItem(key: string): Promise<IFile | null> {
|
|
43
|
+
const parameters = {
|
|
44
|
+
Bucket: this.config.bucket,
|
|
45
|
+
Key: this.config.pathPrefix + '/' + key,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const { Body, ContentType, ContentEncoding } = await this.s3.send(new GetObjectCommand(parameters));
|
|
50
|
+
|
|
51
|
+
// const blob = new Blob([await Body?.transformToByteArray()!]);
|
|
52
|
+
|
|
53
|
+
if (ContentEncoding === 'gzip') {
|
|
54
|
+
return {
|
|
55
|
+
type: validateMimeType(ContentType),
|
|
56
|
+
data: await ungzip(await Body!.transformToByteArray()),
|
|
57
|
+
};
|
|
58
|
+
} else {
|
|
59
|
+
return {
|
|
60
|
+
type: validateMimeType(ContentType),
|
|
61
|
+
data: (await Body!.transformToByteArray()) as Buffer,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if (error instanceof Error && error.name.match(/^NoSuchKey/)) {
|
|
66
|
+
return null;
|
|
67
|
+
} else {
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public async removeItem(key: string): Promise<void> {
|
|
74
|
+
TODO_USE(key);
|
|
75
|
+
throw new NotYetImplementedError(`DigitalOceanSpaces.removeItem is not implemented yet`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public async setItem(key: string, file: IFile): Promise<void> {
|
|
79
|
+
// TODO: Put putObjectRequestAdditional into processedFile
|
|
80
|
+
const putObjectRequestAdditional: Partial<PutObjectCommandInput> = {};
|
|
81
|
+
|
|
82
|
+
let processedFile: IFile;
|
|
83
|
+
if (this.config.gzip) {
|
|
84
|
+
const gzipped = await gzip(file.data);
|
|
85
|
+
const sizePercentageAfterCompression = gzipped.byteLength / file.data.byteLength;
|
|
86
|
+
if (sizePercentageAfterCompression < 0.7) {
|
|
87
|
+
// consolex.log(`Gzipping ${key} (${Math.floor(sizePercentageAfterCompression * 100)}%)`);
|
|
88
|
+
processedFile = { ...file, data: gzipped };
|
|
89
|
+
putObjectRequestAdditional.ContentEncoding = 'gzip';
|
|
90
|
+
} else {
|
|
91
|
+
processedFile = file;
|
|
92
|
+
// consolex.log(`NOT Gzipping ${key} (${Math.floor(sizePercentageAfterCompression * 100)}%)`);
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
processedFile = file;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const uploadResult = await this.s3.send(
|
|
99
|
+
new PutObjectCommand({
|
|
100
|
+
Bucket: this.config.bucket,
|
|
101
|
+
Key: this.config.pathPrefix + '/' + key,
|
|
102
|
+
ContentType: processedFile.type,
|
|
103
|
+
...putObjectRequestAdditional,
|
|
104
|
+
Body: processedFile.data,
|
|
105
|
+
// TODO: Public read access / just private to extending class
|
|
106
|
+
ACL: 'public-read',
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
if (!uploadResult.ETag) {
|
|
111
|
+
throw new Error(`Upload result does not contain ETag`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* TODO: Implement Read-only mode
|
|
118
|
+
* TODO: [☹️] Unite with `PromptbookStorage` and move to `/src/...`
|
|
119
|
+
*/
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { string_mime_type } from '../../../../../../src/types/typeAliases';
|
|
2
|
+
import type { IStorage } from './IStorage';
|
|
3
|
+
|
|
4
|
+
export type IFile = {
|
|
5
|
+
// Maybe TODO name: string_name;
|
|
6
|
+
type: string_mime_type;
|
|
7
|
+
data: Buffer;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Represents storage that will store each keypair in a separate file.
|
|
12
|
+
*/
|
|
13
|
+
export type IFilesStorage = Omit<IStorage<IFile>, 'length' | 'clear' | 'key'>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Represents storage that can give public deterministic URL for each file
|
|
17
|
+
*/
|
|
18
|
+
export type IIFilesStorageWithCdn = IFilesStorage & {
|
|
19
|
+
readonly cdnPublicUrl: URL;
|
|
20
|
+
getItemUrl(key: string): URL;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* TODO: Probably not deterministic and async getItemUrl
|
|
25
|
+
* TODO: Probably just createUrlMaker
|
|
26
|
+
* TODO: List method
|
|
27
|
+
* TODO: Glob method
|
|
28
|
+
* TODO: Subfolder (similar to PrefixStorage) method
|
|
29
|
+
* TODO: Subscribe, list, sub(folder) should be part of LIB everstorage
|
|
30
|
+
* TODO: Probably implement observe through RxJS
|
|
31
|
+
* TODO: [☹️] Unite with `PromptbookStorage` and move to `/src/...`
|
|
32
|
+
*/
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Note: This is a simplified version of the IStorage interface based on the usage in the project.
|
|
2
|
+
export type IStorage<T> = {
|
|
3
|
+
readonly length: Promise<number>;
|
|
4
|
+
clear(): Promise<void>;
|
|
5
|
+
getItem(key: string): Promise<T | null>;
|
|
6
|
+
key(index: number): Promise<string | null>;
|
|
7
|
+
removeItem(key: string): Promise<void>;
|
|
8
|
+
setItem(key: string, value: T): Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* TODO: [☹️] Unite with `PromptbookStorage` and move to `/src/...`
|
|
14
|
+
*/
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import hexEncoder from 'crypto-js/enc-hex';
|
|
2
|
+
import sha256 from 'crypto-js/sha256';
|
|
3
|
+
import type { string_uri } from '../../../../../../src/types/typeAliases';
|
|
4
|
+
import { titleToName } from '../../../../../../src/utils/normalization/titleToName';
|
|
5
|
+
import { nameToSubfolderPath } from './nameToSubfolderPath';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generates a path for the user content
|
|
9
|
+
*/
|
|
10
|
+
export function getUserFileCdnKey(file: Buffer, originalFilename: string): string_uri {
|
|
11
|
+
const hash = sha256(hexEncoder.parse(file.toString('hex'))).toString(/* hex */);
|
|
12
|
+
// <- TODO: [🥬] Encapsulate sha256 to some private utility function
|
|
13
|
+
|
|
14
|
+
const originalFilenameParts = originalFilename.split('.');
|
|
15
|
+
const extension = originalFilenameParts.pop();
|
|
16
|
+
const name = titleToName(originalFilenameParts.join('.'));
|
|
17
|
+
|
|
18
|
+
const filename = name + '.' + extension;
|
|
19
|
+
// <- Note: [⛳️] Preserving original file name
|
|
20
|
+
|
|
21
|
+
return `user/files/${nameToSubfolderPath(hash).join('/')}/${filename}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* TODO: [🌍] Unite this logic in one place
|
|
26
|
+
* TODO: Way to garbage unused uploaded files
|
|
27
|
+
* TODO: Probably separate util countBufferHash
|
|
28
|
+
*/
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { string_name } from '../../../../../../src/types/typeAliases';
|
|
2
|
+
|
|
3
|
+
export function nameToSubfolderPath(name: string_name): Array<string> {
|
|
4
|
+
return [name.substr(0, 2).toLowerCase(), name.substr(2, 5).toLowerCase()];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* TODO: !!! Use `nameToSubfolderPath` from src
|
|
9
|
+
*/
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TODO_any } from '@promptbook-local/types';
|
|
2
|
+
import { NextRequest } from 'next/server';
|
|
3
|
+
import { Readable } from 'node:stream';
|
|
4
|
+
|
|
5
|
+
export async function nextRequestToNodeRequest(nextRequest: NextRequest): Promise<Readable> {
|
|
6
|
+
const reader = nextRequest.body?.getReader();
|
|
7
|
+
|
|
8
|
+
if (!reader) {
|
|
9
|
+
throw new Error(`Can not get nextRequest.body.getReader()`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const nodeStream = new Readable({
|
|
13
|
+
async read() {
|
|
14
|
+
const { done, value } = await reader.read();
|
|
15
|
+
if (done) this.push(null);
|
|
16
|
+
else this.push(Buffer.from(value));
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Fake IncomingMessage with headers
|
|
21
|
+
(nodeStream as TODO_any).headers = Object.fromEntries(nextRequest.headers.entries());
|
|
22
|
+
(nodeStream as TODO_any).method = nextRequest.method;
|
|
23
|
+
(nodeStream as TODO_any).url = nextRequest.url;
|
|
24
|
+
(nodeStream as TODO_any).socket = {}; // required by formidable
|
|
25
|
+
|
|
26
|
+
return nodeStream;
|
|
27
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { string_mime_type } from '../../../../../src/types/typeAliases';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks if the value is valid mime-type
|
|
5
|
+
*
|
|
6
|
+
* @param value candidate for mime-type
|
|
7
|
+
* @returns the value if it is valid mime-type
|
|
8
|
+
* @throws TypeError if the value is not valid mime-type
|
|
9
|
+
*/
|
|
10
|
+
export function validateMimeType(value: unknown): string_mime_type {
|
|
11
|
+
if (typeof value !== 'string') {
|
|
12
|
+
throw new TypeError(`Mime-type must be string, but it is ${typeof value}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!/^[a-z]+\/(?:[a-z0-9]+[.-])*[a-z0-9]+$/i.test(value)) {
|
|
16
|
+
throw new TypeError(`Invalid mime-type "${value}"`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return value as string_mime_type;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* TODO: [🧠] Move to main Promptbook utils
|
|
24
|
+
*/
|
|
@@ -24,6 +24,6 @@
|
|
|
24
24
|
"@promptbook-local/*": ["../../src/_packages/*.index"]
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
|
-
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
27
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "../_common/hooks/usePromise.ts"],
|
|
28
28
|
"exclude": ["node_modules"]
|
|
29
29
|
}
|