@gencow/core 0.1.27 → 0.1.28
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/document-types.d.ts +65 -0
- package/dist/document-types.js +15 -0
- package/dist/grounded-answer-types.d.ts +62 -0
- package/dist/grounded-answer-types.js +6 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.js +4 -0
- package/dist/rag-ingest-types.d.ts +39 -0
- package/dist/rag-ingest-types.js +1 -0
- package/dist/rag-operations-types.d.ts +81 -0
- package/dist/rag-operations-types.js +1 -0
- package/dist/rag-schema.d.ts +1557 -0
- package/dist/rag-schema.js +87 -0
- package/dist/reactive.d.ts +13 -0
- package/dist/rls-db.d.ts +9 -2
- package/dist/runtime-env-policy.d.ts +5 -0
- package/dist/runtime-env-policy.js +56 -0
- package/dist/search-types.d.ts +83 -0
- package/dist/search-types.js +1 -0
- package/dist/server.d.ts +1 -2
- package/dist/server.js +0 -1
- package/dist/storage-shared.d.ts +36 -0
- package/dist/storage-shared.js +39 -0
- package/dist/storage.d.ts +2 -26
- package/dist/storage.js +19 -15
- package/dist/workflow-types.d.ts +3 -1
- package/package.json +8 -7
- package/src/document-types.ts +95 -0
- package/src/grounded-answer-types.ts +78 -0
- package/src/index.ts +66 -1
- package/src/rag-ingest-types.ts +52 -0
- package/src/rag-operations-types.ts +90 -0
- package/src/rag-schema.ts +94 -0
- package/src/reactive.ts +13 -0
- package/src/rls-db.ts +9 -4
- package/src/runtime-env-policy.ts +66 -0
- package/src/search-types.ts +91 -0
- package/src/server.ts +1 -2
- package/src/storage-shared.ts +74 -0
- package/src/storage.ts +29 -46
- package/src/workflow-types.ts +3 -1
- package/src/__tests__/auth.test.ts +0 -118
- package/src/__tests__/crons.test.ts +0 -83
- package/src/__tests__/crud-codegen-integration.test.ts +0 -246
- package/src/__tests__/crud-owner-rls.test.ts +0 -387
- package/src/__tests__/crud.test.ts +0 -930
- package/src/__tests__/dist-exports.test.ts +0 -176
- package/src/__tests__/fixtures/basic/auth.ts +0 -32
- package/src/__tests__/fixtures/basic/drizzle.config.ts +0 -12
- package/src/__tests__/fixtures/basic/index.ts +0 -6
- package/src/__tests__/fixtures/basic/migrations/0000_last_warstar.sql +0 -75
- package/src/__tests__/fixtures/basic/migrations/meta/0000_snapshot.json +0 -497
- package/src/__tests__/fixtures/basic/migrations/meta/_journal.json +0 -13
- package/src/__tests__/fixtures/basic/schema.ts +0 -51
- package/src/__tests__/fixtures/basic/tasks.ts +0 -15
- package/src/__tests__/fixtures/common/auth-schema.ts +0 -67
- package/src/__tests__/helpers/basic-rls-fixture.ts +0 -135
- package/src/__tests__/helpers/pglite-migrations.ts +0 -32
- package/src/__tests__/helpers/pglite-rls-session.ts +0 -51
- package/src/__tests__/helpers/seed-like-fill.ts +0 -202
- package/src/__tests__/helpers/test-gencow-ctx-rls.ts +0 -50
- package/src/__tests__/httpaction.test.ts +0 -122
- package/src/__tests__/image-optimization.test.ts +0 -648
- package/src/__tests__/load.test.ts +0 -389
- package/src/__tests__/network-sim.test.ts +0 -319
- package/src/__tests__/reactive.test.ts +0 -479
- package/src/__tests__/retry.test.ts +0 -113
- package/src/__tests__/rls-crud-basic.test.ts +0 -317
- package/src/__tests__/rls-crud-no-owner-rls-pglite.test.ts +0 -117
- package/src/__tests__/rls-custom-mutation-handlers.test.ts +0 -142
- package/src/__tests__/rls-custom-query-handlers.test.ts +0 -128
- package/src/__tests__/rls-db-leased-connection.test.ts +0 -118
- package/src/__tests__/rls-session-and-policies.test.ts +0 -228
- package/src/__tests__/scheduler-durable-v2.test.ts +0 -288
- package/src/__tests__/scheduler-durable.test.ts +0 -173
- package/src/__tests__/scheduler-exec.test.ts +0 -328
- package/src/__tests__/scheduler.test.ts +0 -187
- package/src/__tests__/storage.test.ts +0 -334
- package/src/__tests__/tsconfig.json +0 -8
- package/src/__tests__/validator.test.ts +0 -323
- package/src/__tests__/workflow.test.ts +0 -606
- package/src/__tests__/ws-integration.test.ts +0 -309
- package/src/__tests__/ws-scale.test.ts +0 -241
- package/src/auth.ts +0 -155
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { SearchFilter, SearchScope } from "./search-types.js";
|
|
2
|
+
|
|
3
|
+
export type CitationCoverage = "direct" | "partial" | "context";
|
|
4
|
+
export type ClaimSupportStatus = "supported" | "partially_supported" | "insufficient_evidence";
|
|
5
|
+
export type GroundedAnswerMode = "qa" | "compare" | "topic";
|
|
6
|
+
|
|
7
|
+
export type Citation = {
|
|
8
|
+
sourceId: string;
|
|
9
|
+
sourceTitle: string;
|
|
10
|
+
sectionId?: string;
|
|
11
|
+
sectionPath?: string[];
|
|
12
|
+
pageStart?: number;
|
|
13
|
+
pageEnd?: number;
|
|
14
|
+
chunkIds: string[];
|
|
15
|
+
snippet: string;
|
|
16
|
+
coverage: CitationCoverage;
|
|
17
|
+
confidence: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type ClaimEvidenceMap = {
|
|
21
|
+
claimId: string;
|
|
22
|
+
claimText: string;
|
|
23
|
+
status: ClaimSupportStatus;
|
|
24
|
+
citations: Citation[];
|
|
25
|
+
missingEvidenceReasons?: string[];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type GroundedAnswer = {
|
|
29
|
+
answer: string;
|
|
30
|
+
claims: ClaimEvidenceMap[];
|
|
31
|
+
citations: Citation[];
|
|
32
|
+
warnings: string[];
|
|
33
|
+
grounded: boolean;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type GroundingBudget = {
|
|
37
|
+
maxVerifyLoops: number;
|
|
38
|
+
maxResearchQueriesPerLoop: number;
|
|
39
|
+
maxCitationsPerClaim: number;
|
|
40
|
+
maxClaimsPerAnswer: number;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const DEFAULT_GROUNDING_BUDGET: GroundingBudget = {
|
|
44
|
+
maxVerifyLoops: 2,
|
|
45
|
+
maxResearchQueriesPerLoop: 3,
|
|
46
|
+
maxCitationsPerClaim: 3,
|
|
47
|
+
maxClaimsPerAnswer: 12,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type GroundedClaimInput = {
|
|
51
|
+
claimId?: string;
|
|
52
|
+
claimText: string;
|
|
53
|
+
requiredTerms?: string[];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type GroundedCompareInput = {
|
|
57
|
+
left: string;
|
|
58
|
+
right: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type GroundedTopicInput = {
|
|
62
|
+
minDistinctSections?: number;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type GroundedAnswerInput = {
|
|
66
|
+
question: string;
|
|
67
|
+
scope: SearchScope;
|
|
68
|
+
filters?: SearchFilter;
|
|
69
|
+
claims?: GroundedClaimInput[];
|
|
70
|
+
mode?: GroundedAnswerMode;
|
|
71
|
+
compare?: GroundedCompareInput;
|
|
72
|
+
topic?: GroundedTopicInput;
|
|
73
|
+
budget?: Partial<GroundingBudget>;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export type GroundingRuntime = {
|
|
77
|
+
answer(input: GroundedAnswerInput): Promise<GroundedAnswer>;
|
|
78
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -20,6 +20,70 @@ export type {
|
|
|
20
20
|
AIMessage,
|
|
21
21
|
AIResult,
|
|
22
22
|
} from "./reactive.js";
|
|
23
|
+
export type {
|
|
24
|
+
SearchPrimitive,
|
|
25
|
+
SearchScope,
|
|
26
|
+
SearchFilter,
|
|
27
|
+
SearchOptions,
|
|
28
|
+
VectorSearchOptions,
|
|
29
|
+
HybridSearchOptions,
|
|
30
|
+
SearchHit,
|
|
31
|
+
SearchResponse,
|
|
32
|
+
SearchTierConfig,
|
|
33
|
+
} from "./search-types.js";
|
|
34
|
+
export type {
|
|
35
|
+
DocumentVisibility,
|
|
36
|
+
DocumentConvertMode,
|
|
37
|
+
DocumentConvertProvider,
|
|
38
|
+
DocumentResolvedProvider,
|
|
39
|
+
DocumentConvertInput,
|
|
40
|
+
DocumentPage,
|
|
41
|
+
DocumentSection,
|
|
42
|
+
DocumentProviderTrace,
|
|
43
|
+
DocumentConvertResult,
|
|
44
|
+
DocumentCacheArtifact,
|
|
45
|
+
DocumentCacheKeyInput,
|
|
46
|
+
GencowServicesCtx,
|
|
47
|
+
WorkflowDocumentServicesCtx,
|
|
48
|
+
} from "./document-types.js";
|
|
49
|
+
export { buildDocumentCacheKey } from "./document-types.js";
|
|
50
|
+
export type {
|
|
51
|
+
RagIngestReindexMode,
|
|
52
|
+
RagIngestInput,
|
|
53
|
+
RagIngestWorkflowArgs,
|
|
54
|
+
RagIngestStartResult,
|
|
55
|
+
RagIngestJobStatus,
|
|
56
|
+
RagIngestJobRecord,
|
|
57
|
+
} from "./rag-ingest-types.js";
|
|
58
|
+
export type {
|
|
59
|
+
CitationCoverage,
|
|
60
|
+
ClaimSupportStatus,
|
|
61
|
+
GroundedAnswerMode,
|
|
62
|
+
Citation,
|
|
63
|
+
ClaimEvidenceMap,
|
|
64
|
+
GroundedAnswer,
|
|
65
|
+
GroundingBudget,
|
|
66
|
+
GroundedClaimInput,
|
|
67
|
+
GroundedCompareInput,
|
|
68
|
+
GroundedTopicInput,
|
|
69
|
+
GroundedAnswerInput,
|
|
70
|
+
GroundingRuntime,
|
|
71
|
+
} from "./grounded-answer-types.js";
|
|
72
|
+
export { DEFAULT_GROUNDING_BUDGET } from "./grounded-answer-types.js";
|
|
73
|
+
export type {
|
|
74
|
+
RagOperationKind,
|
|
75
|
+
RagOperationMetricUnit,
|
|
76
|
+
RagIndexHealth,
|
|
77
|
+
RagOperationMetric,
|
|
78
|
+
RagOperationsSummary,
|
|
79
|
+
RagEvaluationExpectedClaim,
|
|
80
|
+
RagEvaluationFixture,
|
|
81
|
+
RagEvaluationFixtureResult,
|
|
82
|
+
RagEvaluationRunResult,
|
|
83
|
+
RagReindexMode,
|
|
84
|
+
RagReindexPlan,
|
|
85
|
+
} from "./rag-operations-types.js";
|
|
86
|
+
export { ragCorpora, ragSources, ragSections, ragChunks, ragIngestJobs, ragOperationMetrics } from "./rag-schema.js";
|
|
23
87
|
export {
|
|
24
88
|
query,
|
|
25
89
|
mutation,
|
|
@@ -36,7 +100,7 @@ export {
|
|
|
36
100
|
getRegisteredMutations,
|
|
37
101
|
getRegisteredHttpActions,
|
|
38
102
|
} from "./reactive.js";
|
|
39
|
-
export type { Storage } from "./storage.js";
|
|
103
|
+
export type { Storage, StoredFile } from "./storage.js";
|
|
40
104
|
export { createScheduler, getSchedulerInfo } from "./scheduler.js";
|
|
41
105
|
export type {
|
|
42
106
|
Scheduler,
|
|
@@ -82,6 +146,7 @@ export { v, parseArgs, GencowValidationError } from "./v.js";
|
|
|
82
146
|
export type { Validator, Infer, InferArgs } from "./v.js";
|
|
83
147
|
export { withRetry } from "./retry.js";
|
|
84
148
|
export type { RetryOptions } from "./retry.js";
|
|
149
|
+
export { filterTenantRuntimeEnvVars, isReservedTenantRuntimeEnvKey } from "./runtime-env-policy.js";
|
|
85
150
|
export { cronJobs } from "./crons.js";
|
|
86
151
|
export type { CronJobsBuilder, CronJobDef, IntervalOptions, DailyOptions, WeeklyOptions } from "./crons.js";
|
|
87
152
|
export { defineAuth } from "./auth-config.js";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { DocumentConvertProvider, DocumentConvertMode, DocumentProviderTrace, DocumentVisibility } from "./document-types.js";
|
|
2
|
+
|
|
3
|
+
export type RagIngestReindexMode = "if_changed" | "force";
|
|
4
|
+
export type RagIngestJobStatus =
|
|
5
|
+
| "queued"
|
|
6
|
+
| "converting"
|
|
7
|
+
| "chunking"
|
|
8
|
+
| "embedding"
|
|
9
|
+
| "upserting"
|
|
10
|
+
| "completed"
|
|
11
|
+
| "failed"
|
|
12
|
+
| "canceled";
|
|
13
|
+
|
|
14
|
+
export type RagIngestInput = {
|
|
15
|
+
storageId: string;
|
|
16
|
+
corpus: string;
|
|
17
|
+
visibility: DocumentVisibility;
|
|
18
|
+
ownerUserId?: string;
|
|
19
|
+
sourceKey?: string;
|
|
20
|
+
metadata?: Record<string, unknown>;
|
|
21
|
+
reindexMode?: RagIngestReindexMode;
|
|
22
|
+
mode?: DocumentConvertMode;
|
|
23
|
+
provider?: DocumentConvertProvider;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type RagIngestWorkflowArgs = RagIngestInput & {
|
|
27
|
+
jobId: string;
|
|
28
|
+
sourceId: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type RagIngestStartResult = {
|
|
32
|
+
workflowId: string;
|
|
33
|
+
jobId: string;
|
|
34
|
+
sourceId: string;
|
|
35
|
+
status: "queued";
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type RagIngestJobRecord = {
|
|
39
|
+
id: string;
|
|
40
|
+
workflowId: string;
|
|
41
|
+
sourceId: string;
|
|
42
|
+
corpus: string;
|
|
43
|
+
visibility: DocumentVisibility;
|
|
44
|
+
ownerUserId: string | null;
|
|
45
|
+
status: RagIngestJobStatus;
|
|
46
|
+
stage: string;
|
|
47
|
+
providerTrace: Partial<DocumentProviderTrace> | Record<string, never>;
|
|
48
|
+
metrics: Record<string, unknown>;
|
|
49
|
+
error: string | null;
|
|
50
|
+
startedAt: string;
|
|
51
|
+
completedAt: string | null;
|
|
52
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { SearchScope } from "./search-types.js";
|
|
2
|
+
|
|
3
|
+
export type RagOperationKind = "ingest" | "retrieve" | "answer" | "reindex" | "evaluate";
|
|
4
|
+
export type RagOperationMetricUnit = "ms" | "count" | "tokens" | "usd";
|
|
5
|
+
export type RagIndexHealth = "ready" | "empty" | "degraded" | "failed";
|
|
6
|
+
|
|
7
|
+
export type RagOperationMetric = {
|
|
8
|
+
id: string;
|
|
9
|
+
appId: string;
|
|
10
|
+
corpus: string;
|
|
11
|
+
visibility: SearchScope["visibility"];
|
|
12
|
+
ownerUserId: string | null;
|
|
13
|
+
operation: RagOperationKind;
|
|
14
|
+
jobId: string | null;
|
|
15
|
+
workflowId: string | null;
|
|
16
|
+
sourceId: string | null;
|
|
17
|
+
metricName: string;
|
|
18
|
+
metricValue: number;
|
|
19
|
+
unit: RagOperationMetricUnit | null;
|
|
20
|
+
metadata: Record<string, unknown>;
|
|
21
|
+
recordedAt: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type RagOperationsSummary = {
|
|
25
|
+
corpus: string;
|
|
26
|
+
visibility: SearchScope["visibility"];
|
|
27
|
+
ownerUserId: string | null;
|
|
28
|
+
sourceCount: number;
|
|
29
|
+
sectionCount: number;
|
|
30
|
+
chunkCount: number;
|
|
31
|
+
jobCounts: Record<string, number>;
|
|
32
|
+
latestJob: {
|
|
33
|
+
id: string;
|
|
34
|
+
status: string;
|
|
35
|
+
stage: string;
|
|
36
|
+
updatedAt: string;
|
|
37
|
+
} | null;
|
|
38
|
+
recentMetricCounts: Record<string, number>;
|
|
39
|
+
averageLatencyMs: number | null;
|
|
40
|
+
indexHealth: RagIndexHealth;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type RagEvaluationExpectedClaim = {
|
|
44
|
+
claim: string;
|
|
45
|
+
verdict: "supported" | "partial" | "unsupported";
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type RagEvaluationFixture = {
|
|
49
|
+
name: string;
|
|
50
|
+
scope: SearchScope;
|
|
51
|
+
query: string;
|
|
52
|
+
expectedSourceIds?: string[];
|
|
53
|
+
expectedCitationCountMin?: number;
|
|
54
|
+
expectedClaims?: RagEvaluationExpectedClaim[];
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type RagEvaluationFixtureResult = {
|
|
58
|
+
name: string;
|
|
59
|
+
ok: boolean;
|
|
60
|
+
failures: string[];
|
|
61
|
+
matchedSourceIds: string[];
|
|
62
|
+
citationCount: number;
|
|
63
|
+
claimStatuses: Array<{
|
|
64
|
+
claim: string;
|
|
65
|
+
expected: RagEvaluationExpectedClaim["verdict"];
|
|
66
|
+
actual: string | null;
|
|
67
|
+
}>;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export type RagEvaluationRunResult = {
|
|
71
|
+
ok: boolean;
|
|
72
|
+
total: number;
|
|
73
|
+
passed: number;
|
|
74
|
+
failed: number;
|
|
75
|
+
results: RagEvaluationFixtureResult[];
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export type RagReindexMode = "source-changed" | "section-changed" | "corpus-policy-changed" | "full-rebuild";
|
|
79
|
+
|
|
80
|
+
export type RagReindexPlan = {
|
|
81
|
+
corpus: string;
|
|
82
|
+
visibility: SearchScope["visibility"];
|
|
83
|
+
ownerUserId: string | null;
|
|
84
|
+
mode: RagReindexMode;
|
|
85
|
+
reason: string;
|
|
86
|
+
sourceIds: string[];
|
|
87
|
+
sourceCount: number;
|
|
88
|
+
estimatedChunkCount: number;
|
|
89
|
+
requiresConfirmation: boolean;
|
|
90
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { bigint, boolean, doublePrecision, integer, jsonb, pgTable, text, timestamp, vector } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
function buildScopeColumns() {
|
|
4
|
+
return {
|
|
5
|
+
id: text("id").primaryKey(),
|
|
6
|
+
corpus: text("corpus").notNull(),
|
|
7
|
+
visibilityScope: text("visibility_scope").notNull(),
|
|
8
|
+
ownerUserId: text("owner_user_id"),
|
|
9
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
10
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const ragCorpora = pgTable("rag_corpora", {
|
|
15
|
+
...buildScopeColumns(),
|
|
16
|
+
title: text("title").notNull(),
|
|
17
|
+
description: text("description"),
|
|
18
|
+
allowExternalProviders: boolean("allow_external_providers").default(false).notNull(),
|
|
19
|
+
retentionDays: integer("retention_days"),
|
|
20
|
+
metadata: jsonb("metadata").default({}).notNull(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const ragSources = pgTable("rag_sources", {
|
|
24
|
+
...buildScopeColumns(),
|
|
25
|
+
storageId: text("storage_id").notNull(),
|
|
26
|
+
sourceKey: text("source_key").notNull(),
|
|
27
|
+
sourceTitle: text("source_title").notNull(),
|
|
28
|
+
mimeType: text("mime_type").notNull(),
|
|
29
|
+
byteSize: bigint("byte_size", { mode: "number" }).notNull(),
|
|
30
|
+
sourceChecksum: text("source_checksum").notNull(),
|
|
31
|
+
convertProvider: text("convert_provider").notNull(),
|
|
32
|
+
convertStatus: text("convert_status").notNull(),
|
|
33
|
+
markdown: text("markdown").notNull(),
|
|
34
|
+
text: text("text").notNull(),
|
|
35
|
+
warnings: jsonb("warnings").default([]).notNull(),
|
|
36
|
+
metadata: jsonb("metadata").default({}).notNull(),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const ragSections = pgTable("rag_sections", {
|
|
40
|
+
...buildScopeColumns(),
|
|
41
|
+
sourceId: text("source_id").notNull(),
|
|
42
|
+
sectionIndex: integer("section_index").notNull(),
|
|
43
|
+
sectionPath: jsonb("section_path").default([]).notNull(),
|
|
44
|
+
title: text("title"),
|
|
45
|
+
depth: integer("depth").notNull(),
|
|
46
|
+
pageStart: integer("page_start"),
|
|
47
|
+
pageEnd: integer("page_end"),
|
|
48
|
+
charStart: integer("char_start").notNull(),
|
|
49
|
+
charEnd: integer("char_end").notNull(),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export const ragChunks = pgTable("rag_chunks", {
|
|
53
|
+
...buildScopeColumns(),
|
|
54
|
+
sourceId: text("source_id").notNull(),
|
|
55
|
+
sectionId: text("section_id"),
|
|
56
|
+
chunkIndex: integer("chunk_index").notNull(),
|
|
57
|
+
chunkText: text("chunk_text").notNull(),
|
|
58
|
+
lexicalText: text("lexical_text").notNull(),
|
|
59
|
+
embedding: vector("embedding", { dimensions: 1536 }),
|
|
60
|
+
pageStart: integer("page_start"),
|
|
61
|
+
pageEnd: integer("page_end"),
|
|
62
|
+
chunkChecksum: text("chunk_checksum").notNull(),
|
|
63
|
+
metadata: jsonb("metadata").default({}).notNull(),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
export const ragIngestJobs = pgTable("rag_ingest_jobs", {
|
|
67
|
+
...buildScopeColumns(),
|
|
68
|
+
workflowId: text("workflow_id").notNull(),
|
|
69
|
+
sourceId: text("source_id").notNull(),
|
|
70
|
+
status: text("status").notNull(),
|
|
71
|
+
stage: text("stage").notNull(),
|
|
72
|
+
providerTrace: jsonb("provider_trace").default({}).notNull(),
|
|
73
|
+
metrics: jsonb("metrics").default({}).notNull(),
|
|
74
|
+
error: text("error"),
|
|
75
|
+
startedAt: timestamp("started_at").defaultNow().notNull(),
|
|
76
|
+
completedAt: timestamp("completed_at"),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export const ragOperationMetrics = pgTable("rag_operation_metrics", {
|
|
80
|
+
id: text("id").primaryKey(),
|
|
81
|
+
appId: text("app_id").notNull(),
|
|
82
|
+
corpus: text("corpus").notNull(),
|
|
83
|
+
visibilityScope: text("visibility_scope").notNull(),
|
|
84
|
+
ownerUserId: text("owner_user_id"),
|
|
85
|
+
operation: text("operation").notNull(),
|
|
86
|
+
jobId: text("job_id"),
|
|
87
|
+
workflowId: text("workflow_id"),
|
|
88
|
+
sourceId: text("source_id"),
|
|
89
|
+
metricName: text("metric_name").notNull(),
|
|
90
|
+
metricValue: doublePrecision("metric_value").notNull(),
|
|
91
|
+
unit: text("unit"),
|
|
92
|
+
metadata: jsonb("metadata").default({}).notNull(),
|
|
93
|
+
recordedAt: timestamp("recorded_at").defaultNow().notNull(),
|
|
94
|
+
});
|
package/src/reactive.ts
CHANGED
|
@@ -2,6 +2,9 @@ import type { WSContext } from "hono/ws";
|
|
|
2
2
|
import type { Storage } from "./storage.js";
|
|
3
3
|
import type { Scheduler } from "./scheduler.js";
|
|
4
4
|
import { type Validator, type InferArgs } from "./v.js";
|
|
5
|
+
import type { HybridSearchOptions, SearchOptions, SearchResponse, VectorSearchOptions } from "./search-types.js";
|
|
6
|
+
import type { GencowServicesCtx } from "./document-types.js";
|
|
7
|
+
import type { GroundingRuntime } from "./grounded-answer-types.js";
|
|
5
8
|
|
|
6
9
|
// ─── GencowCtx — 사용자 함수에 주입되는 컨텍스트 ──────────
|
|
7
10
|
|
|
@@ -107,8 +110,18 @@ export interface GencowCtx {
|
|
|
107
110
|
realtime: RealtimeCtx;
|
|
108
111
|
/** 재시도 — ctx.retry(fn, opts) — exponential backoff + jitter */
|
|
109
112
|
retry: <T>(fn: () => Promise<T>, options?: import("./retry.js").RetryOptions) => Promise<T>;
|
|
113
|
+
/** 프레임워크 서비스 헬퍼 — workflow 전용 service는 별도 ctx에서 노출 */
|
|
114
|
+
services: GencowServicesCtx;
|
|
110
115
|
/** AI 헬퍼 */
|
|
111
116
|
ai?: AIContext;
|
|
117
|
+
/** Full-text / hybrid search helper */
|
|
118
|
+
search: (table: string, query: string, options: SearchOptions) => Promise<SearchResponse>;
|
|
119
|
+
/** Vector / semantic search helper */
|
|
120
|
+
vectorSearch: (table: string, options: VectorSearchOptions) => Promise<SearchResponse>;
|
|
121
|
+
/** Hybrid search helper (lexical + vector) */
|
|
122
|
+
hybridSearch: (table: string, query: string, options: HybridSearchOptions) => Promise<SearchResponse>;
|
|
123
|
+
/** Grounded answer helper over canonical rag_* tables */
|
|
124
|
+
grounding?: GroundingRuntime;
|
|
112
125
|
}
|
|
113
126
|
|
|
114
127
|
// ─── Types ──────────────────────────────────────────────
|
package/src/rls-db.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import { sql } from "drizzle-orm";
|
|
3
|
-
import type { PgAsyncDatabase } from "drizzle-orm/pg-core";
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* RLS DB wrapper — execution paths for `withRlsConnection`:
|
|
@@ -33,6 +32,12 @@ const gucNameRe = /^app\.[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)*$/;
|
|
|
33
32
|
|
|
34
33
|
const RESERVED_VARS_KEYS = new Set(["app.current_user_id", "app.current_user_role", "app.tenant_id"]);
|
|
35
34
|
|
|
35
|
+
type RlsDrizzleDatabaseLike = {
|
|
36
|
+
session: unknown;
|
|
37
|
+
_: { session?: unknown };
|
|
38
|
+
transaction: (callback: (tx: unknown) => unknown | Promise<unknown>, ...rest: unknown[]) => Promise<unknown>;
|
|
39
|
+
};
|
|
40
|
+
|
|
36
41
|
function assertSafeGucName(key: string): void {
|
|
37
42
|
if (!gucNameRe.test(key)) {
|
|
38
43
|
throw new Error(
|
|
@@ -244,10 +249,10 @@ function wrapSession(session: any, rls: RlsSessionContext, reuseOuterConnection:
|
|
|
244
249
|
*
|
|
245
250
|
* `db.transaction()` still injects the same variables at the start of the callback transaction.
|
|
246
251
|
*/
|
|
247
|
-
export function createRlsDb(
|
|
248
|
-
db:
|
|
252
|
+
export function createRlsDb<TDb extends RlsDrizzleDatabaseLike>(
|
|
253
|
+
db: TDb,
|
|
249
254
|
rls: RlsSessionContext,
|
|
250
|
-
):
|
|
255
|
+
): TDb {
|
|
251
256
|
const reuseOuterConnection = isDrizzleTransactionDb(db);
|
|
252
257
|
const baseSession = (db as unknown as { session: any }).session;
|
|
253
258
|
const wrappedSession = wrapSession(baseSession, rls, reuseOuterConnection);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const RESERVED_TENANT_RUNTIME_ENV_KEYS = new Set([
|
|
2
|
+
"PORT",
|
|
3
|
+
"DATABASE_URL",
|
|
4
|
+
"GENCOW_DB_URL",
|
|
5
|
+
"BETTER_AUTH_SECRET",
|
|
6
|
+
"BETTER_AUTH_URL",
|
|
7
|
+
"IS_PLATFORM",
|
|
8
|
+
"GENCOW_PLATFORM_CONFIG_FILE",
|
|
9
|
+
"GENCOW_PLATFORM_URL",
|
|
10
|
+
"GENCOW_PLATFORM_DB",
|
|
11
|
+
"PLATFORM_OPENAI_KEY",
|
|
12
|
+
"PLATFORM_GOOGLE_KEY",
|
|
13
|
+
"PLATFORM_INTERNAL_SECRET",
|
|
14
|
+
"INVITE_ONLY",
|
|
15
|
+
"RUNNER_TYPE",
|
|
16
|
+
"PGBOUNCER_PORT",
|
|
17
|
+
"GENCOW_FUNCTIONS",
|
|
18
|
+
"GENCOW_STORAGE",
|
|
19
|
+
"GENCOW_MIGRATIONS",
|
|
20
|
+
"GENCOW_APP_NAME",
|
|
21
|
+
"GENCOW_APP_DATA_DIR",
|
|
22
|
+
"GENCOW_INTERNAL_TOKEN",
|
|
23
|
+
"GENCOW_CRON_TOKEN",
|
|
24
|
+
"GENCOW_AI_PROXY_URL",
|
|
25
|
+
"GENCOW_AI_PROXY_URL_ALT",
|
|
26
|
+
"GENCOW_AI_PROXY_TOKEN",
|
|
27
|
+
"GENCOW_METERING_URL",
|
|
28
|
+
"GENCOW_METERING_URL_ALT",
|
|
29
|
+
"GENCOW_START_REASON",
|
|
30
|
+
"GENCOW_RESTART_ID",
|
|
31
|
+
"GENCOW_SHUTDOWN_MARKER_PATH",
|
|
32
|
+
"GENCOW_SKIP_MIGRATION",
|
|
33
|
+
"GENCOW_DB_MAX_CONNECTIONS",
|
|
34
|
+
"GENCOW_MEMORY_MB",
|
|
35
|
+
"BUN_JSC_forceRAMSize",
|
|
36
|
+
"MIMALLOC_PURGE_DELAY",
|
|
37
|
+
"NODE_PATH",
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
const RESERVED_TENANT_RUNTIME_ENV_PREFIXES = ["__GENCOW_", "GENCOW_DOCUMENT_", "GENCOW_WARM_"];
|
|
41
|
+
|
|
42
|
+
export function isReservedTenantRuntimeEnvKey(key: string): boolean {
|
|
43
|
+
const normalized = key.trim();
|
|
44
|
+
return (
|
|
45
|
+
RESERVED_TENANT_RUNTIME_ENV_KEYS.has(normalized) ||
|
|
46
|
+
RESERVED_TENANT_RUNTIME_ENV_PREFIXES.some((prefix) => normalized.startsWith(prefix))
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function filterTenantRuntimeEnvVars(vars: Record<string, string>): {
|
|
51
|
+
allowed: Record<string, string>;
|
|
52
|
+
rejectedKeys: string[];
|
|
53
|
+
} {
|
|
54
|
+
const allowed: Record<string, string> = {};
|
|
55
|
+
const rejectedKeys: string[] = [];
|
|
56
|
+
|
|
57
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
58
|
+
if (isReservedTenantRuntimeEnvKey(key)) {
|
|
59
|
+
rejectedKeys.push(key);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
allowed[key] = value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { allowed, rejectedKeys };
|
|
66
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export type SearchPrimitive = string | number | boolean;
|
|
2
|
+
|
|
3
|
+
export type SearchScope = {
|
|
4
|
+
corpus: string;
|
|
5
|
+
visibility: "private" | "shared" | "public";
|
|
6
|
+
ownerUserId?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type SearchFilter = {
|
|
10
|
+
eq?: Record<string, SearchPrimitive>;
|
|
11
|
+
in?: Record<string, SearchPrimitive[]>;
|
|
12
|
+
range?: Record<string, { gte?: string | number; lte?: string | number }>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type SearchOptions = {
|
|
16
|
+
fields: [string, ...string[]];
|
|
17
|
+
limit?: number;
|
|
18
|
+
offset?: number;
|
|
19
|
+
filters?: SearchFilter;
|
|
20
|
+
scope: SearchScope;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type VectorSearchTuning = {
|
|
24
|
+
minScore?: number;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type VectorSearchOptions = Omit<SearchOptions, "fields"> & {
|
|
28
|
+
vector: number[];
|
|
29
|
+
vectorField?: string;
|
|
30
|
+
tuning?: VectorSearchTuning;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type HybridSearchFusionTuning = {
|
|
34
|
+
mode?: "rrf";
|
|
35
|
+
rrfK?: number;
|
|
36
|
+
keywordWeight?: number;
|
|
37
|
+
vectorWeight?: number;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type HybridSearchTuning = {
|
|
41
|
+
keywordCandidateLimit?: number;
|
|
42
|
+
vectorCandidateLimit?: number;
|
|
43
|
+
minFusedScore?: number;
|
|
44
|
+
fusion?: HybridSearchFusionTuning;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type HybridSearchOptions = SearchOptions & {
|
|
48
|
+
vector: number[];
|
|
49
|
+
vectorField?: string;
|
|
50
|
+
fusion?: "rrf"; // legacy top-level compatibility
|
|
51
|
+
keywordCandidateLimit?: number; // legacy top-level compatibility
|
|
52
|
+
vectorCandidateLimit?: number; // legacy top-level compatibility
|
|
53
|
+
tuning?: HybridSearchTuning;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type SearchHit = {
|
|
57
|
+
id: string | number;
|
|
58
|
+
row: Record<string, unknown>;
|
|
59
|
+
score: number;
|
|
60
|
+
scores?: {
|
|
61
|
+
keyword?: number;
|
|
62
|
+
vector?: number;
|
|
63
|
+
fused?: number;
|
|
64
|
+
};
|
|
65
|
+
matchedBy: Array<"keyword" | "vector">;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type SearchResponse = {
|
|
69
|
+
items: SearchHit[];
|
|
70
|
+
meta: {
|
|
71
|
+
engine: "tsvector" | "pgroonga";
|
|
72
|
+
tier: "free" | "pro" | "scale";
|
|
73
|
+
limit: number;
|
|
74
|
+
offset: number;
|
|
75
|
+
nextOffset?: number;
|
|
76
|
+
fusion?: "rrf";
|
|
77
|
+
mode?: "keyword" | "vector" | "hybrid";
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export type SearchTierConfig = {
|
|
82
|
+
plan: "free" | "pro" | "scale";
|
|
83
|
+
engine: "tsvector" | "pgroonga";
|
|
84
|
+
hybridSearch: boolean;
|
|
85
|
+
locale: "english" | "multilingual";
|
|
86
|
+
extensions: {
|
|
87
|
+
vector: boolean;
|
|
88
|
+
pgroonga: boolean;
|
|
89
|
+
};
|
|
90
|
+
degradedReason?: string;
|
|
91
|
+
};
|
package/src/server.ts
CHANGED
|
@@ -6,6 +6,5 @@
|
|
|
6
6
|
* bundled into user functions which run in Firecracker.
|
|
7
7
|
*/
|
|
8
8
|
export { createStorage, storageRoutes } from "./storage.js";
|
|
9
|
-
export type { StorageImageTierConfig } from "./storage.js";
|
|
9
|
+
export type { StorageImageTierConfig, StoredFile } from "./storage.js";
|
|
10
10
|
export { createScheduler, getSchedulerInfo } from "./scheduler.js";
|
|
11
|
-
export { authMiddleware, authRoutes, getUsers } from "./auth.js";
|