create-m5kdev 0.40.3 → 0.41.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/package.json +1 -1
- package/templates/minimal-app/.cursor/rules/frontend-component-guide.mdc +95 -95
- package/templates/minimal-app/.cursor/rules/frontend-data-guide.mdc +103 -103
- package/templates/minimal-app/.cursor/rules/frontend-form-guide.mdc +80 -80
- package/templates/minimal-app/.cursor/rules/frontend-hook-guide.mdc +79 -79
- package/templates/minimal-app/.cursor/rules/frontend-i18n-guide.mdc +45 -45
- package/templates/minimal-app/.cursor/rules/module-dto-guide.mdc +60 -60
- package/templates/minimal-app/.cursor/rules/module-prompt-guide.mdc +214 -214
- package/templates/minimal-app/.cursor/rules/module-repository-guide.mdc +167 -167
- package/templates/minimal-app/.cursor/rules/module-schema-guide.mdc +53 -53
- package/templates/minimal-app/.cursor/rules/module-service-guide.mdc +367 -367
- package/templates/minimal-app/.cursor/rules/module-trpc-guide.mdc +71 -71
- package/templates/minimal-app/apps/.gitignore.tpl +13 -13
- package/templates/minimal-app/apps/e2e/package.json.tpl +23 -23
- package/templates/minimal-app/apps/e2e/tests/standard.spec.ts.tpl +11 -22
- package/templates/minimal-app/apps/email/package.json.tpl +34 -34
- package/templates/minimal-app/apps/expo/.gitignore.tpl +44 -44
- package/templates/minimal-app/apps/expo/.prettierignore +13 -13
- package/templates/minimal-app/apps/expo/.prettierrc.json.tpl +9 -9
- package/templates/minimal-app/apps/expo/CHANGELOG.md.tpl +156 -156
- package/templates/minimal-app/apps/expo/README.md.tpl +44 -44
- package/templates/minimal-app/apps/expo/package.json.tpl +63 -63
- package/templates/minimal-app/apps/landing/package.json.tpl +34 -34
- package/templates/minimal-app/apps/server/drizzle/0000_whole_echo.sql +366 -366
- package/templates/minimal-app/apps/server/drizzle/0002_crazy_lilith.sql +46 -46
- package/templates/minimal-app/apps/server/drizzle/0003_freezing_fantastic_four.sql +3 -3
- package/templates/minimal-app/apps/server/drizzle/0004_slow_ezekiel_stane.sql +98 -98
- package/templates/minimal-app/apps/server/drizzle/0005_wonderful_the_professor.sql +1 -1
- package/templates/minimal-app/apps/server/drizzle/0006_lazy_blue_marvel.sql +158 -158
- package/templates/minimal-app/apps/server/drizzle/0007_abnormal_ultimo.sql +1 -1
- package/templates/minimal-app/apps/server/drizzle/0008_steady_nekra.sql +86 -86
- package/templates/minimal-app/apps/server/drizzle/0009_empty_starjammers.sql +45 -0
- package/templates/minimal-app/apps/server/drizzle/meta/0000_snapshot.json.tpl +2624 -2624
- package/templates/minimal-app/apps/server/drizzle/meta/0001_snapshot.json.tpl +2670 -2670
- package/templates/minimal-app/apps/server/drizzle/meta/0002_snapshot.json.tpl +2715 -2715
- package/templates/minimal-app/apps/server/drizzle/meta/0003_snapshot.json.tpl +2687 -2687
- package/templates/minimal-app/apps/server/drizzle/meta/0004_snapshot.json.tpl +2497 -2497
- package/templates/minimal-app/apps/server/drizzle/meta/0005_snapshot.json.tpl +2483 -2483
- package/templates/minimal-app/apps/server/drizzle/meta/0006_snapshot.json.tpl +3602 -3602
- package/templates/minimal-app/apps/server/drizzle/meta/0007_snapshot.json.tpl +3619 -3619
- package/templates/minimal-app/apps/server/drizzle/meta/0008_snapshot.json.tpl +3619 -3619
- package/templates/minimal-app/apps/server/drizzle/meta/0009_snapshot.json.tpl +3687 -0
- package/templates/minimal-app/apps/server/drizzle/meta/_journal.json.tpl +8 -1
- package/templates/minimal-app/apps/server/package.json.tpl +57 -57
- package/templates/minimal-app/apps/shared/package.json.tpl +27 -27
- package/templates/minimal-app/apps/webapp/AGENTS.md.tpl +24 -24
- package/templates/minimal-app/apps/webapp/index.html.tpl +22 -22
- package/templates/minimal-app/apps/webapp/package.json.tpl +53 -53
- package/templates/minimal-app/apps/webapp/public/logo.svg.tpl +6 -6
- package/templates/minimal-app/pnpm-workspace.yaml.tpl +15 -15
- package/templates/minimal-app/apps/expo/expo-env.d.ts.tpl +0 -3
- package/templates/minimal-app/apps/expo/uniwind-types.d.ts.tpl +0 -10
|
@@ -1,214 +1,214 @@
|
|
|
1
|
-
---
|
|
2
|
-
globs: apps/**/server/src/modules/**/*.prompt.ts
|
|
3
|
-
alwaysApply: false
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Module Prompt File Style Guide
|
|
7
|
-
|
|
8
|
-
Conventions for complex AI prompt modules. A prompt file owns the complete
|
|
9
|
-
configuration for one AI operation and exposes it through one factory
|
|
10
|
-
function. Callers should not need to know how the prompt, schema, model
|
|
11
|
-
settings, or extraction strategy are assembled.
|
|
12
|
-
|
|
13
|
-
## File Location
|
|
14
|
-
|
|
15
|
-
```text
|
|
16
|
-
apps/<app>/server/src/modules/<module>/<use-case>.prompt.ts
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Use one file per AI use case. If a module has unrelated operations, split them
|
|
20
|
-
into separate prompt files instead of exporting multiple factories from one
|
|
21
|
-
file.
|
|
22
|
-
|
|
23
|
-
## Core Contract
|
|
24
|
-
|
|
25
|
-
- The only exported runtime value is one named factory function:
|
|
26
|
-
`create<UseCase>Prompt(...)`.
|
|
27
|
-
- The factory is synchronous and returns the options object for exactly one of:
|
|
28
|
-
`AIService.agentText`, `AIService.agentObject`, `AIService.generateText`, or
|
|
29
|
-
`AIService.generateObject`.
|
|
30
|
-
- The consumer passes the returned object directly to the chosen AI method.
|
|
31
|
-
- Keep prompt templates, Zod schemas, lookup tables, rules, and helper
|
|
32
|
-
functions private to the file.
|
|
33
|
-
- Export types only when another module genuinely needs them; do not export
|
|
34
|
-
internal prompt-building details.
|
|
35
|
-
- Do not call `AIService` from a prompt file. Prompt modules build parameters;
|
|
36
|
-
services own execution, error handling, and orchestration.
|
|
37
|
-
|
|
38
|
-
For agent methods, the factory returns the method's second argument. The agent
|
|
39
|
-
name remains explicit at the service call site.
|
|
40
|
-
|
|
41
|
-
```ts
|
|
42
|
-
await this.service.ai.agentText("researcher", createResearchPrompt(input));
|
|
43
|
-
await this.service.ai.agentObject("classifier", createClassificationPrompt(input));
|
|
44
|
-
await this.service.ai.generateText(createSummaryPrompt(input));
|
|
45
|
-
await this.service.ai.generateObject(createEntryPrompt(input));
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Spread extra prompt configuration into the result at the call site (like adding `ctx` if needed). If
|
|
49
|
-
an option is part of the use case, accept the relevant domain input and decide
|
|
50
|
-
the option inside the factory.
|
|
51
|
-
|
|
52
|
-
## Type the Returned Parameters
|
|
53
|
-
|
|
54
|
-
Use the public parameter types for direct generation:
|
|
55
|
-
|
|
56
|
-
```ts
|
|
57
|
-
import type {
|
|
58
|
-
AIServiceGenerateObjectParams,
|
|
59
|
-
AIServiceGenerateTextParams,
|
|
60
|
-
} from "@m5kdev/backend/modules/ai/ai.service";
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
For agent options, derive the second-argument type from `AIService`:
|
|
64
|
-
|
|
65
|
-
```ts
|
|
66
|
-
import type { AIService } from "@m5kdev/backend/modules/ai/ai.service";
|
|
67
|
-
|
|
68
|
-
type AgentTextPromptOptions = Parameters<AIService["agentText"]>[1];
|
|
69
|
-
type AgentObjectPromptOptions = Parameters<AIService["agentObject"]>[1];
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Prefer an explicit return type. When `satisfies` preserves a concrete schema
|
|
73
|
-
more accurately, return the object with `satisfies` instead.
|
|
74
|
-
|
|
75
|
-
## Canonical Object Prompt
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
import { Prompt } from "@m5kdev/backend/modules/ai/ai.prompt";
|
|
79
|
-
import type { AIServiceGenerateObjectParams } from "@m5kdev/backend/modules/ai/ai.service";
|
|
80
|
-
import { z } from "zod";
|
|
81
|
-
|
|
82
|
-
type CreateEntryPromptParams = {
|
|
83
|
-
transcript: string;
|
|
84
|
-
category: "diary" | "review";
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const entrySchema = z.object({
|
|
88
|
-
title: z.string().describe("A short entry title"),
|
|
89
|
-
content: z.string().describe("The formatted entry in Markdown"),
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const categoryInstructions = {
|
|
93
|
-
diary: "Preserve the personal, chronological voice.",
|
|
94
|
-
review: "Organize the subject, impressions, and overall opinion.",
|
|
95
|
-
} as const;
|
|
96
|
-
|
|
97
|
-
const entryPrompt = new Prompt<{
|
|
98
|
-
transcript: string;
|
|
99
|
-
instructions: string;
|
|
100
|
-
}>(`
|
|
101
|
-
<instructions>
|
|
102
|
-
{{instructions}}
|
|
103
|
-
</instructions>
|
|
104
|
-
|
|
105
|
-
<transcript>
|
|
106
|
-
{{transcript}}
|
|
107
|
-
</transcript>
|
|
108
|
-
`);
|
|
109
|
-
|
|
110
|
-
export function createEntryPrompt(
|
|
111
|
-
params: CreateEntryPromptParams
|
|
112
|
-
): AIServiceGenerateObjectParams<typeof entrySchema> {
|
|
113
|
-
return {
|
|
114
|
-
schema: entrySchema,
|
|
115
|
-
presetModels: {
|
|
116
|
-
category: "creative",
|
|
117
|
-
tokenProfile: "lg",
|
|
118
|
-
},
|
|
119
|
-
prompt: entryPrompt.compile({
|
|
120
|
-
transcript: params.transcript,
|
|
121
|
-
instructions: categoryInstructions[params.category],
|
|
122
|
-
}),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
The service consumes it without reconstructing or overriding its options:
|
|
128
|
-
|
|
129
|
-
```ts
|
|
130
|
-
return this.service.ai.generateObject(createEntryPrompt(input));
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## Text and Agent Variants
|
|
134
|
-
|
|
135
|
-
### `generateText`
|
|
136
|
-
|
|
137
|
-
```ts
|
|
138
|
-
export function createSummaryPrompt(
|
|
139
|
-
params: SummaryPromptParams
|
|
140
|
-
): AIServiceGenerateTextParams {
|
|
141
|
-
return {
|
|
142
|
-
prompt: summaryPrompt.compile(params),
|
|
143
|
-
presetModels: { category: "chat", tokenProfile: "md" },
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### `agentText`
|
|
149
|
-
|
|
150
|
-
```ts
|
|
151
|
-
type AgentTextPromptOptions = Parameters<AIService["agentText"]>[1];
|
|
152
|
-
|
|
153
|
-
export function createResearchPrompt(
|
|
154
|
-
params: ResearchPromptParams
|
|
155
|
-
): AgentTextPromptOptions {
|
|
156
|
-
return {
|
|
157
|
-
prompt: researchPrompt.compile(params),
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### `agentObject`
|
|
163
|
-
|
|
164
|
-
```ts
|
|
165
|
-
type AgentObjectPromptOptions = Parameters<AIService["agentObject"]>[1];
|
|
166
|
-
|
|
167
|
-
export function createClassificationPrompt(params: ClassificationPromptParams) {
|
|
168
|
-
return {
|
|
169
|
-
schema: classificationSchema,
|
|
170
|
-
prompt: classificationPrompt.compile(params),
|
|
171
|
-
} satisfies AgentObjectPromptOptions;
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
## Complex Prompt Composition
|
|
176
|
-
|
|
177
|
-
Complexity belongs behind the factory boundary:
|
|
178
|
-
|
|
179
|
-
- Define reusable `Prompt<Context>` instances at module scope and call
|
|
180
|
-
`.compile(...)` only inside the factory.
|
|
181
|
-
- Use typed lookup maps for category-, locale-, or mode-specific instructions.
|
|
182
|
-
- Select dynamic schemas and `safeSchema` inside the factory.
|
|
183
|
-
- Keep static rules in named constants rather than one enormous interpolated
|
|
184
|
-
template.
|
|
185
|
-
- Put model preferences, retry settings, token profiles, and other generation
|
|
186
|
-
options in the returned object.
|
|
187
|
-
- Return either `prompt` or `messages` according to the target method's type;
|
|
188
|
-
do not build both.
|
|
189
|
-
- Accept domain data such as transcript, category, or locale. Do not accept an
|
|
190
|
-
`AIService`, repository, request context, or other execution dependency.
|
|
191
|
-
- Keep the factory deterministic and free of I/O, logging, mutation, and
|
|
192
|
-
environment reads.
|
|
193
|
-
|
|
194
|
-
## Do Not
|
|
195
|
-
|
|
196
|
-
```ts
|
|
197
|
-
// Wrong: exports raw building blocks and makes every caller assemble options.
|
|
198
|
-
export const prompt = new Prompt(...);
|
|
199
|
-
export const schema = z.object(...);
|
|
200
|
-
|
|
201
|
-
// Wrong: returns only a compiled string instead of method parameters.
|
|
202
|
-
export function createEntryPrompt(input: Input) {
|
|
203
|
-
return prompt.compile(input);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Wrong: executes the AI operation in the prompt module.
|
|
207
|
-
export async function createEntryPrompt(ai: AIService, input: Input) {
|
|
208
|
-
return ai.generateObject({ schema, prompt: prompt.compile(input) });
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Wrong: multiple public prompt factories in one use-case file.
|
|
212
|
-
export function createEntryPrompt(...) { ... }
|
|
213
|
-
export function createTitlePrompt(...) { ... }
|
|
214
|
-
```
|
|
1
|
+
---
|
|
2
|
+
globs: apps/**/server/src/modules/**/*.prompt.ts
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Module Prompt File Style Guide
|
|
7
|
+
|
|
8
|
+
Conventions for complex AI prompt modules. A prompt file owns the complete
|
|
9
|
+
configuration for one AI operation and exposes it through one factory
|
|
10
|
+
function. Callers should not need to know how the prompt, schema, model
|
|
11
|
+
settings, or extraction strategy are assembled.
|
|
12
|
+
|
|
13
|
+
## File Location
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
apps/<app>/server/src/modules/<module>/<use-case>.prompt.ts
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Use one file per AI use case. If a module has unrelated operations, split them
|
|
20
|
+
into separate prompt files instead of exporting multiple factories from one
|
|
21
|
+
file.
|
|
22
|
+
|
|
23
|
+
## Core Contract
|
|
24
|
+
|
|
25
|
+
- The only exported runtime value is one named factory function:
|
|
26
|
+
`create<UseCase>Prompt(...)`.
|
|
27
|
+
- The factory is synchronous and returns the options object for exactly one of:
|
|
28
|
+
`AIService.agentText`, `AIService.agentObject`, `AIService.generateText`, or
|
|
29
|
+
`AIService.generateObject`.
|
|
30
|
+
- The consumer passes the returned object directly to the chosen AI method.
|
|
31
|
+
- Keep prompt templates, Zod schemas, lookup tables, rules, and helper
|
|
32
|
+
functions private to the file.
|
|
33
|
+
- Export types only when another module genuinely needs them; do not export
|
|
34
|
+
internal prompt-building details.
|
|
35
|
+
- Do not call `AIService` from a prompt file. Prompt modules build parameters;
|
|
36
|
+
services own execution, error handling, and orchestration.
|
|
37
|
+
|
|
38
|
+
For agent methods, the factory returns the method's second argument. The agent
|
|
39
|
+
name remains explicit at the service call site.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
await this.service.ai.agentText("researcher", createResearchPrompt(input));
|
|
43
|
+
await this.service.ai.agentObject("classifier", createClassificationPrompt(input));
|
|
44
|
+
await this.service.ai.generateText(createSummaryPrompt(input));
|
|
45
|
+
await this.service.ai.generateObject(createEntryPrompt(input));
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Spread extra prompt configuration into the result at the call site (like adding `ctx` if needed). If
|
|
49
|
+
an option is part of the use case, accept the relevant domain input and decide
|
|
50
|
+
the option inside the factory.
|
|
51
|
+
|
|
52
|
+
## Type the Returned Parameters
|
|
53
|
+
|
|
54
|
+
Use the public parameter types for direct generation:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import type {
|
|
58
|
+
AIServiceGenerateObjectParams,
|
|
59
|
+
AIServiceGenerateTextParams,
|
|
60
|
+
} from "@m5kdev/backend/modules/ai/ai.service";
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For agent options, derive the second-argument type from `AIService`:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import type { AIService } from "@m5kdev/backend/modules/ai/ai.service";
|
|
67
|
+
|
|
68
|
+
type AgentTextPromptOptions = Parameters<AIService["agentText"]>[1];
|
|
69
|
+
type AgentObjectPromptOptions = Parameters<AIService["agentObject"]>[1];
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Prefer an explicit return type. When `satisfies` preserves a concrete schema
|
|
73
|
+
more accurately, return the object with `satisfies` instead.
|
|
74
|
+
|
|
75
|
+
## Canonical Object Prompt
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { Prompt } from "@m5kdev/backend/modules/ai/ai.prompt";
|
|
79
|
+
import type { AIServiceGenerateObjectParams } from "@m5kdev/backend/modules/ai/ai.service";
|
|
80
|
+
import { z } from "zod";
|
|
81
|
+
|
|
82
|
+
type CreateEntryPromptParams = {
|
|
83
|
+
transcript: string;
|
|
84
|
+
category: "diary" | "review";
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const entrySchema = z.object({
|
|
88
|
+
title: z.string().describe("A short entry title"),
|
|
89
|
+
content: z.string().describe("The formatted entry in Markdown"),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const categoryInstructions = {
|
|
93
|
+
diary: "Preserve the personal, chronological voice.",
|
|
94
|
+
review: "Organize the subject, impressions, and overall opinion.",
|
|
95
|
+
} as const;
|
|
96
|
+
|
|
97
|
+
const entryPrompt = new Prompt<{
|
|
98
|
+
transcript: string;
|
|
99
|
+
instructions: string;
|
|
100
|
+
}>(`
|
|
101
|
+
<instructions>
|
|
102
|
+
{{instructions}}
|
|
103
|
+
</instructions>
|
|
104
|
+
|
|
105
|
+
<transcript>
|
|
106
|
+
{{transcript}}
|
|
107
|
+
</transcript>
|
|
108
|
+
`);
|
|
109
|
+
|
|
110
|
+
export function createEntryPrompt(
|
|
111
|
+
params: CreateEntryPromptParams
|
|
112
|
+
): AIServiceGenerateObjectParams<typeof entrySchema> {
|
|
113
|
+
return {
|
|
114
|
+
schema: entrySchema,
|
|
115
|
+
presetModels: {
|
|
116
|
+
category: "creative",
|
|
117
|
+
tokenProfile: "lg",
|
|
118
|
+
},
|
|
119
|
+
prompt: entryPrompt.compile({
|
|
120
|
+
transcript: params.transcript,
|
|
121
|
+
instructions: categoryInstructions[params.category],
|
|
122
|
+
}),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The service consumes it without reconstructing or overriding its options:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
return this.service.ai.generateObject(createEntryPrompt(input));
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Text and Agent Variants
|
|
134
|
+
|
|
135
|
+
### `generateText`
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
export function createSummaryPrompt(
|
|
139
|
+
params: SummaryPromptParams
|
|
140
|
+
): AIServiceGenerateTextParams {
|
|
141
|
+
return {
|
|
142
|
+
prompt: summaryPrompt.compile(params),
|
|
143
|
+
presetModels: { category: "chat", tokenProfile: "md" },
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `agentText`
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
type AgentTextPromptOptions = Parameters<AIService["agentText"]>[1];
|
|
152
|
+
|
|
153
|
+
export function createResearchPrompt(
|
|
154
|
+
params: ResearchPromptParams
|
|
155
|
+
): AgentTextPromptOptions {
|
|
156
|
+
return {
|
|
157
|
+
prompt: researchPrompt.compile(params),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### `agentObject`
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
type AgentObjectPromptOptions = Parameters<AIService["agentObject"]>[1];
|
|
166
|
+
|
|
167
|
+
export function createClassificationPrompt(params: ClassificationPromptParams) {
|
|
168
|
+
return {
|
|
169
|
+
schema: classificationSchema,
|
|
170
|
+
prompt: classificationPrompt.compile(params),
|
|
171
|
+
} satisfies AgentObjectPromptOptions;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Complex Prompt Composition
|
|
176
|
+
|
|
177
|
+
Complexity belongs behind the factory boundary:
|
|
178
|
+
|
|
179
|
+
- Define reusable `Prompt<Context>` instances at module scope and call
|
|
180
|
+
`.compile(...)` only inside the factory.
|
|
181
|
+
- Use typed lookup maps for category-, locale-, or mode-specific instructions.
|
|
182
|
+
- Select dynamic schemas and `safeSchema` inside the factory.
|
|
183
|
+
- Keep static rules in named constants rather than one enormous interpolated
|
|
184
|
+
template.
|
|
185
|
+
- Put model preferences, retry settings, token profiles, and other generation
|
|
186
|
+
options in the returned object.
|
|
187
|
+
- Return either `prompt` or `messages` according to the target method's type;
|
|
188
|
+
do not build both.
|
|
189
|
+
- Accept domain data such as transcript, category, or locale. Do not accept an
|
|
190
|
+
`AIService`, repository, request context, or other execution dependency.
|
|
191
|
+
- Keep the factory deterministic and free of I/O, logging, mutation, and
|
|
192
|
+
environment reads.
|
|
193
|
+
|
|
194
|
+
## Do Not
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
// Wrong: exports raw building blocks and makes every caller assemble options.
|
|
198
|
+
export const prompt = new Prompt(...);
|
|
199
|
+
export const schema = z.object(...);
|
|
200
|
+
|
|
201
|
+
// Wrong: returns only a compiled string instead of method parameters.
|
|
202
|
+
export function createEntryPrompt(input: Input) {
|
|
203
|
+
return prompt.compile(input);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Wrong: executes the AI operation in the prompt module.
|
|
207
|
+
export async function createEntryPrompt(ai: AIService, input: Input) {
|
|
208
|
+
return ai.generateObject({ schema, prompt: prompt.compile(input) });
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Wrong: multiple public prompt factories in one use-case file.
|
|
212
|
+
export function createEntryPrompt(...) { ... }
|
|
213
|
+
export function createTitlePrompt(...) { ... }
|
|
214
|
+
```
|