@happyvertical/smrt-prompts 0.30.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/AGENTS.md ADDED
@@ -0,0 +1,36 @@
1
+ # smrt-prompts
2
+
3
+ SMRT prompt registry and tenant-aware prompt override package. Code defines defaults; config layers and DB-stored overrides personalize at app and tenant levels.
4
+
5
+ ## Core pieces
6
+
7
+ - `definePrompt()` registers code defaults in a global process registry (`globalThis.__smrtPromptRegistry`)
8
+ - `resolvePrompt()` merges code defaults, file/config overrides (via `@happyvertical/smrt-config`), stored app-level overrides, stored tenant-level overrides, and a runtime override
9
+ - `PromptOverride` (`_smrt_prompt_overrides` table) stores partial app-level and tenant-level overrides with write-time validation
10
+ - `PromptOverrideCollection` exposes the standard SmrtCollection CRUD surface
11
+
12
+ ## Resolution layers (priority low → high)
13
+
14
+ 1. Code default — registered via `definePrompt({ key, template, ai })`
15
+ 2. File/config override — `getPackageConfig<PromptPackageConfig>('prompts', defaults)`
16
+ 3. App-level stored override — `PromptOverride` row with `tenantId = null`
17
+ 4. Tenant-level stored override — `PromptOverride` row with current tenant
18
+ 5. Runtime override — passed to `resolvePrompt({ overrides })`
19
+
20
+ Each layer can override any subset of fields (template, profile, model, params). Inheritance is field-by-field.
21
+
22
+ ## Conventions
23
+
24
+ - **Namespace prompt keys** by package or domain: `projects.issue.incorporateFeedback`, `content.summarize.headline`
25
+ - **Stored overrides use nullable fields** so inheritance stays field-by-field — null means "use the lower layer"
26
+ - **Provider selection is indirect** in v1: prompts select named profiles, and profiles resolve to provider/model in `smrt-config`
27
+ - **`editable` flags are enforced on `PromptOverride.save()`** — definitions can lock specific fields against tenant override
28
+
29
+ ## Caching
30
+
31
+ `resolvePrompt()` results are cached per `(key, tenantId)` with a TTL. The cache is invalidated on `PromptOverride.save()` and `.delete()`. Use `clearPromptCache()` for manual invalidation in tests.
32
+
33
+ ## Related
34
+
35
+ - `@happyvertical/smrt-languages` — parallel package for language strings (uses the same architecture pattern)
36
+ - `@happyvertical/smrt-features` — parallel package for feature flags
package/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ @AGENTS.md
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright <2025> <Happy Vertical Corporation>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @happyvertical/smrt-prompts
2
+
3
+ Typed prompt definitions, tenant-aware prompt overrides, and runtime prompt resolution for SMRT applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @happyvertical/smrt-prompts
9
+ ```
10
+
11
+ ## Quick start
12
+
13
+ ```typescript
14
+ import { definePrompt, resolvePrompt } from '@happyvertical/smrt-prompts';
15
+
16
+ // 1. Register a prompt's defaults at startup
17
+ definePrompt({
18
+ key: 'projects.issue.incorporateFeedback',
19
+ template: 'Rewrite the issue body incorporating this feedback: {feedback}',
20
+ ai: {
21
+ profile: 'default',
22
+ params: { temperature: 0.4 },
23
+ },
24
+ });
25
+
26
+ // 2. Resolve at runtime (auto-uses tenant context from AsyncLocalStorage)
27
+ const resolved = await resolvePrompt('projects.issue.incorporateFeedback', {
28
+ vars: { feedback: '...' },
29
+ });
30
+
31
+ // resolved.template — the merged template with overrides applied
32
+ // resolved.ai — the merged AI configuration (profile, model, params)
33
+ ```
34
+
35
+ ## What this package provides
36
+
37
+ - **`definePrompt()`** — code-first prompt registration in a global process registry
38
+ - **`resolvePrompt()`** — layered resolution: code default → config override → stored app override → stored tenant override → runtime override
39
+ - **`PromptOverride`** — CRUD model for app-level and tenant-level prompt settings, stored in `_smrt_prompt_overrides`
40
+ - **Named AI profiles** loaded from `packages.prompts` config — prompts select profile names, profiles resolve to provider/model in config
41
+ - **TTL cache** keyed by `(key, tenantId)`, invalidated on override save/delete
42
+
43
+ Stored overrides support partial fields, so applications can override only the template, profile, model, or AI params without forking the rest of a prompt.
44
+
45
+ ## Documentation
46
+
47
+ - See [`AGENTS.md`](./AGENTS.md) for package-internal patterns
48
+ - See [`docs/standards.md`](../../docs/standards.md) for monorepo conventions
49
+ - See related: [`@happyvertical/smrt-languages`](../languages) (mirrors this package for language strings), [`@happyvertical/smrt-features`](../features) (feature flags)
@@ -0,0 +1,169 @@
1
+ import { SmrtClassOptions } from '@happyvertical/smrt-core';
2
+ import { SmrtCollection } from '@happyvertical/smrt-core';
3
+ import { SmrtObject } from '@happyvertical/smrt-core';
4
+ import { SmrtObjectOptions } from '@happyvertical/smrt-core';
5
+
6
+ export declare function clearPromptCache(): void;
7
+
8
+ export declare function definePrompt(input: PromptDefinitionInput): PromptDefinition;
9
+
10
+ export declare function getPromptCacheTtlMs(): number;
11
+
12
+ export declare interface NormalizedPromptAI {
13
+ profile?: string;
14
+ model?: string;
15
+ params: PromptParams;
16
+ }
17
+
18
+ /* Excluded from this release type: PACKAGE_VERSION_INITIALIZED */
19
+
20
+ export declare interface PromptAIInput {
21
+ profile?: string | null;
22
+ model?: string | null;
23
+ params?: PromptParams | null;
24
+ temperature?: number;
25
+ maxTokens?: number;
26
+ [key: string]: unknown;
27
+ }
28
+
29
+ export declare interface PromptConfigOverrideInput {
30
+ template?: string | null;
31
+ profile?: string | null;
32
+ model?: string | null;
33
+ params?: PromptParams | null;
34
+ ai?: PromptAIInput | null;
35
+ temperature?: number;
36
+ maxTokens?: number;
37
+ [key: string]: unknown;
38
+ }
39
+
40
+ export declare interface PromptDefinition {
41
+ key: string;
42
+ template: string;
43
+ ai: NormalizedPromptAI;
44
+ editable: PromptEditableConfig;
45
+ }
46
+
47
+ export declare interface PromptDefinitionInput {
48
+ key: string;
49
+ template: string;
50
+ ai?: PromptAIInput;
51
+ editable?: Partial<PromptEditableConfig>;
52
+ }
53
+
54
+ export declare interface PromptEditableConfig {
55
+ template: boolean;
56
+ profile: boolean;
57
+ model: boolean;
58
+ params: boolean;
59
+ }
60
+
61
+ export declare interface PromptLayer {
62
+ template?: string | null;
63
+ profile?: string | null;
64
+ model?: string | null;
65
+ params?: PromptParams | null;
66
+ }
67
+
68
+ export declare class PromptOverride extends SmrtObject {
69
+ key: string;
70
+ tenantId: string | null;
71
+ template: string | null;
72
+ profile: string | null;
73
+ model: string | null;
74
+ params: string | null;
75
+ constructor(options?: PromptOverrideOptions);
76
+ getParams(): PromptParams;
77
+ setParams(params: PromptParams | null): void;
78
+ toPromptLayer(): PromptLayer;
79
+ save(): Promise<this>;
80
+ private saveAfterIdentityChange;
81
+ private saveAfterIdentityChangeInTransaction;
82
+ private saveAfterIdentityChangeWithDeferredDelete;
83
+ delete(): Promise<void>;
84
+ private validatePromptOverride;
85
+ private getLowerPrecedenceLayers;
86
+ private normalizeParamsForPersistence;
87
+ private getPersistedIdentity;
88
+ }
89
+
90
+ export declare class PromptOverrideCollection extends SmrtCollection<PromptOverride> {
91
+ static readonly _itemClass: typeof PromptOverride;
92
+ private excludeOverrideId;
93
+ getAppOverride(key: string, options?: {
94
+ excludeId?: string;
95
+ }): Promise<PromptOverride | null>;
96
+ getTenantOverride(key: string, tenantId: string, options?: {
97
+ excludeId?: string;
98
+ }): Promise<PromptOverride | null>;
99
+ getResolutionLayers(key: string, tenantId?: string | null, options?: {
100
+ excludeId?: string;
101
+ }): Promise<{
102
+ app: PromptOverride | null;
103
+ tenant: PromptOverride | null;
104
+ }>;
105
+ }
106
+
107
+ export declare interface PromptOverrideOptions extends SmrtObjectOptions {
108
+ key?: string;
109
+ tenantId?: string | null;
110
+ template?: string | null;
111
+ profile?: string | null;
112
+ model?: string | null;
113
+ params?: string | PromptParams | null;
114
+ }
115
+
116
+ export declare interface PromptPackageConfig {
117
+ profiles?: Record<string, PromptProfileConfig>;
118
+ prompts?: Record<string, PromptConfigOverrideInput>;
119
+ allowedProfileNames?: string[];
120
+ allowedModels?: string[];
121
+ [key: string]: unknown;
122
+ }
123
+
124
+ export declare type PromptParams = Record<string, unknown>;
125
+
126
+ export declare interface PromptProfileConfig {
127
+ provider: string;
128
+ model: string;
129
+ params?: PromptParams | null;
130
+ temperature?: number;
131
+ maxTokens?: number;
132
+ [key: string]: unknown;
133
+ }
134
+
135
+ export declare const PromptRegistry: {
136
+ register(input: PromptDefinitionInput): PromptDefinition;
137
+ get(key: string): PromptDefinition | undefined;
138
+ has(key: string): boolean;
139
+ getAll(): PromptDefinition[];
140
+ clear(): void;
141
+ };
142
+
143
+ export declare interface ResolvedPrompt {
144
+ key: string;
145
+ template: string;
146
+ text: string;
147
+ ai: ResolvedPromptAI;
148
+ }
149
+
150
+ export declare interface ResolvedPromptAI extends PromptParams {
151
+ profile?: string;
152
+ provider?: string;
153
+ model?: string;
154
+ allowedModels?: string[];
155
+ params: PromptParams;
156
+ temperature?: number;
157
+ maxTokens?: number;
158
+ }
159
+
160
+ export declare function resolvePrompt(key: string, options?: ResolvePromptOptions): Promise<ResolvedPrompt>;
161
+
162
+ export declare interface ResolvePromptOptions {
163
+ db?: SmrtClassOptions['db'];
164
+ tenantId?: string | null;
165
+ variables?: Record<string, unknown>;
166
+ override?: PromptConfigOverrideInput;
167
+ }
168
+
169
+ export { }