@percepta/create 3.4.1 → 3.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/webapp/AGENTS.md +1 -1
- package/templates/webapp/agent-skills/deploy.md +1 -1
- package/templates/webapp/agent-skills/inngest.md +5 -5
- package/templates/webapp/agent-skills/langfuse.md +4 -4
- package/templates/webapp/agent-skills/llm.md +1 -1
- package/templates/webapp/deploy/README.md +1 -1
- package/templates/webapp/package.json.template +8 -14
- package/templates/webapp/src/app/api/inngest/route.ts +12 -22
- package/templates/webapp/src/instrumentation.ts +2 -63
- package/templates/webapp/src/server/trpc.ts +6 -18
- package/templates/webapp/src/services/AuthContextService.ts +7 -59
- package/templates/webapp/src/services/inngest/InngestService.ts +14 -62
- package/templates/webapp/src/services/langfuse/LangfuseService.ts +9 -77
- package/templates/webapp/src/services/llm/LLMService.ts +10 -88
- package/templates/webapp/src/services/logger/AppLogger.ts +3 -48
- package/templates/webapp/src/utils/syncInngestApp.ts +4 -56
- package/templates/webapp/scripts/deploy-percepta-test.ts +0 -1112
- package/templates/webapp/scripts/open-ryvn-deploy-pr.ts +0 -497
- package/templates/webapp/src/services/inngest/InngestFunctionCollection.ts +0 -5
- package/templates/webapp/src/services/llm/LlmProviderService.ts +0 -85
|
@@ -1,88 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
type
|
|
11
|
-
modelId?: string;
|
|
12
|
-
provider?: LlmProviderName;
|
|
13
|
-
telemetryFunctionId?: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export class LLMService {
|
|
17
|
-
private static SINGLETON: LLMService | undefined;
|
|
18
|
-
|
|
19
|
-
public static create(): LLMService {
|
|
20
|
-
if (LLMService.SINGLETON == null) {
|
|
21
|
-
LLMService.SINGLETON = new LLMService(LlmProviderService.create());
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return LLMService.SINGLETON;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
private constructor(private llmProviderService: LlmProviderService) {}
|
|
28
|
-
|
|
29
|
-
public generateText(
|
|
30
|
-
options: GenerateTextOptions,
|
|
31
|
-
): ReturnType<typeof generateText> {
|
|
32
|
-
const { modelId, provider, telemetryFunctionId, ...generateOptions } =
|
|
33
|
-
options;
|
|
34
|
-
const selection = this.llmProviderService.getLanguageModel({
|
|
35
|
-
modelId,
|
|
36
|
-
provider,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const aiOptions = {
|
|
40
|
-
...generateOptions,
|
|
41
|
-
model: selection.model,
|
|
42
|
-
experimental_telemetry: {
|
|
43
|
-
...generateOptions.experimental_telemetry,
|
|
44
|
-
isEnabled: generateOptions.experimental_telemetry?.isEnabled ?? true,
|
|
45
|
-
functionId:
|
|
46
|
-
telemetryFunctionId ??
|
|
47
|
-
generateOptions.experimental_telemetry?.functionId ??
|
|
48
|
-
"llm.generateText",
|
|
49
|
-
metadata: {
|
|
50
|
-
...generateOptions.experimental_telemetry?.metadata,
|
|
51
|
-
llmProvider: selection.provider,
|
|
52
|
-
llmModel: selection.modelId,
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
} as Parameters<typeof generateText>[0];
|
|
56
|
-
|
|
57
|
-
return generateText(aiOptions);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
public streamText(options: StreamTextOptions): ReturnType<typeof streamText> {
|
|
61
|
-
const { modelId, provider, telemetryFunctionId, ...streamOptions } =
|
|
62
|
-
options;
|
|
63
|
-
const selection = this.llmProviderService.getLanguageModel({
|
|
64
|
-
modelId,
|
|
65
|
-
provider,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const aiOptions = {
|
|
69
|
-
...streamOptions,
|
|
70
|
-
model: selection.model,
|
|
71
|
-
experimental_telemetry: {
|
|
72
|
-
...streamOptions.experimental_telemetry,
|
|
73
|
-
isEnabled: streamOptions.experimental_telemetry?.isEnabled ?? true,
|
|
74
|
-
functionId:
|
|
75
|
-
telemetryFunctionId ??
|
|
76
|
-
streamOptions.experimental_telemetry?.functionId ??
|
|
77
|
-
"llm.streamText",
|
|
78
|
-
metadata: {
|
|
79
|
-
...streamOptions.experimental_telemetry?.metadata,
|
|
80
|
-
llmProvider: selection.provider,
|
|
81
|
-
llmModel: selection.modelId,
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
} as Parameters<typeof streamText>[0];
|
|
85
|
-
|
|
86
|
-
return streamText(aiOptions);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
createPerceptaLlmServiceFactory,
|
|
3
|
+
type PerceptaLlmService,
|
|
4
|
+
} from "@percepta/ai";
|
|
5
|
+
import { getEnvConfig } from "../../config/getEnvConfig";
|
|
6
|
+
|
|
7
|
+
export const LLMService = createPerceptaLlmServiceFactory({
|
|
8
|
+
getConfig: getEnvConfig,
|
|
9
|
+
});
|
|
10
|
+
export type LLMService = PerceptaLlmService;
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type MosaicLogger,
|
|
3
|
-
createLogFactory,
|
|
4
|
-
createTracerFactory,
|
|
5
|
-
} from "@percepta/logger";
|
|
6
|
-
import { assertNever } from "@percepta/utils";
|
|
7
|
-
import pino, { type Logger } from "pino";
|
|
8
|
-
import pretty from "pino-pretty";
|
|
1
|
+
import { createLoggerRuntime } from "@percepta/logger";
|
|
9
2
|
import { getEnvConfig } from "../../config/getEnvConfig";
|
|
10
3
|
|
|
11
4
|
/**
|
|
@@ -19,43 +12,5 @@ import { getEnvConfig } from "../../config/getEnvConfig";
|
|
|
19
12
|
* All logs automatically include request context (reqId, method, path, host)
|
|
20
13
|
* when called within a request scope established by withLogContext().
|
|
21
14
|
*/
|
|
22
|
-
export const { getLogger, withLogContext } =
|
|
23
|
-
|
|
24
|
-
() => new AsyncLocalStorage<MosaicLogger>(),
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Tracer for request context propagation.
|
|
29
|
-
* Uses AsyncLocalStorage to pass trace IDs through async boundaries.
|
|
30
|
-
*/
|
|
31
|
-
export const { getTracer, withTracer } = createTracerFactory(
|
|
32
|
-
() => new AsyncLocalStorage(),
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
// TODO(@dzhao): Generalize this and move to createPinoInstance.ts.
|
|
36
|
-
function createBasePinoInstance(): Logger {
|
|
37
|
-
const { NODE_ENV: nodeEnv, LOG_LEVEL: level } = getEnvConfig();
|
|
38
|
-
|
|
39
|
-
switch (nodeEnv) {
|
|
40
|
-
case "production":
|
|
41
|
-
return pino({
|
|
42
|
-
level,
|
|
43
|
-
formatters: {
|
|
44
|
-
level: (label) => ({ level: label }),
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
case "development":
|
|
48
|
-
case "test":
|
|
49
|
-
// Development: use pino-pretty synchronously (avoids worker thread issues with Next.js/Turbopack)
|
|
50
|
-
return pino(
|
|
51
|
-
{ level },
|
|
52
|
-
pretty({
|
|
53
|
-
colorize: true,
|
|
54
|
-
translateTime: "SYS:standard",
|
|
55
|
-
ignore: "pid,hostname",
|
|
56
|
-
}),
|
|
57
|
-
);
|
|
58
|
-
default:
|
|
59
|
-
return assertNever(nodeEnv);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
15
|
+
export const { getLogger, getTracer, withLogContext, withTracer } =
|
|
16
|
+
createLoggerRuntime({ env: getEnvConfig() });
|
|
@@ -1,62 +1,10 @@
|
|
|
1
|
+
import { syncPerceptaInngestApp } from "@percepta/inngest";
|
|
1
2
|
import { getEnvConfig } from "../config/getEnvConfig";
|
|
2
3
|
import { getLogger } from "../services/logger/AppLogger";
|
|
3
4
|
|
|
4
5
|
export async function syncInngestApp(): Promise<void> {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
APP_BASE_URL: appBaseUrl,
|
|
9
|
-
INNGEST_APP_URL,
|
|
10
|
-
} = getEnvConfig();
|
|
11
|
-
|
|
12
|
-
// Cascade: explicit INNGEST_APP_URL > derived from APP_BASE_URL > localhost fallback
|
|
13
|
-
const appUrl =
|
|
14
|
-
INNGEST_APP_URL ??
|
|
15
|
-
(appBaseUrl
|
|
16
|
-
? `${appBaseUrl}/api/inngest`
|
|
17
|
-
: "http://localhost:3000/api/inngest");
|
|
18
|
-
|
|
19
|
-
if (skipSync) {
|
|
20
|
-
getLogger().info(undefined, "SKIP_INNGEST_SYNC=true, skipping auto-sync");
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// INNGEST_BASE_URL is required
|
|
25
|
-
if (!inngestServerUrl) {
|
|
26
|
-
getLogger().error(
|
|
27
|
-
undefined,
|
|
28
|
-
"INNGEST_BASE_URL environment variable is not set, skipping sync",
|
|
29
|
-
);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const gqlEndpoint = `${inngestServerUrl}/v0/gql`;
|
|
34
|
-
|
|
35
|
-
getLogger().info(
|
|
36
|
-
{ safe: { gqlEndpoint, appUrl } },
|
|
37
|
-
"Syncing with Inngest Server",
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
const payload = {
|
|
41
|
-
operationName: "CreateApp",
|
|
42
|
-
query:
|
|
43
|
-
"mutation CreateApp($input: CreateAppInput!) {\n createApp(input: $input) {\n url\n }\n}\n",
|
|
44
|
-
variables: {
|
|
45
|
-
input: {
|
|
46
|
-
url: appUrl,
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const response = await fetch(gqlEndpoint, {
|
|
52
|
-
method: "POST",
|
|
53
|
-
headers: {
|
|
54
|
-
"Content-Type": "application/json",
|
|
55
|
-
},
|
|
56
|
-
body: JSON.stringify(payload),
|
|
6
|
+
await syncPerceptaInngestApp({
|
|
7
|
+
getEnv: getEnvConfig,
|
|
8
|
+
logger: getLogger(),
|
|
57
9
|
});
|
|
58
|
-
|
|
59
|
-
if (response.ok) {
|
|
60
|
-
getLogger().info(undefined, "Successfully synced with Inngest Server");
|
|
61
|
-
}
|
|
62
10
|
}
|