photon-grid-core 2.0.1 → 2.0.4

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.
Files changed (170) hide show
  1. package/README.md +3 -3
  2. package/cell-selection/cell-selection-engine.d.ts.map +1 -1
  3. package/cell-selection/cell-selection-engine.js +11 -9
  4. package/cell-selection/cell-selection-engine.js.map +1 -1
  5. package/chart/range-chart-controller.d.ts +10 -0
  6. package/chart/range-chart-controller.d.ts.map +1 -1
  7. package/chart/range-chart-controller.js +22 -2
  8. package/chart/range-chart-controller.js.map +1 -1
  9. package/column-groups/column-group-drag-handler.d.ts.map +1 -1
  10. package/column-groups/column-group-drag-handler.js +64 -25
  11. package/column-groups/column-group-drag-handler.js.map +1 -1
  12. package/column-groups/column-group-header-builder.d.ts.map +1 -1
  13. package/column-groups/column-group-header-builder.js +7 -5
  14. package/column-groups/column-group-header-builder.js.map +1 -1
  15. package/column-groups/display-group-drag-handler.d.ts +7 -3
  16. package/column-groups/display-group-drag-handler.d.ts.map +1 -1
  17. package/column-groups/display-group-drag-handler.js +46 -7
  18. package/column-groups/display-group-drag-handler.js.map +1 -1
  19. package/column-groups/display-group-header-builder.d.ts +1 -1
  20. package/column-groups/display-group-header-builder.d.ts.map +1 -1
  21. package/column-groups/display-group-header-builder.js +9 -7
  22. package/column-groups/display-group-header-builder.js.map +1 -1
  23. package/core/column-model.d.ts +88 -5
  24. package/core/column-model.d.ts.map +1 -1
  25. package/core/column-model.js +215 -3
  26. package/core/column-model.js.map +1 -1
  27. package/core/grid-api.d.ts +10 -2
  28. package/core/grid-api.d.ts.map +1 -1
  29. package/core/grid-api.js +10 -0
  30. package/core/grid-api.js.map +1 -1
  31. package/core/grid-core.d.ts +7 -0
  32. package/core/grid-core.d.ts.map +1 -1
  33. package/core/grid-core.js +29 -8
  34. package/core/grid-core.js.map +1 -1
  35. package/core/grid-store.d.ts +5 -5
  36. package/core/grid-store.d.ts.map +1 -1
  37. package/core/pointer-utils.d.ts +59 -0
  38. package/core/pointer-utils.d.ts.map +1 -0
  39. package/core/pointer-utils.js +59 -0
  40. package/core/pointer-utils.js.map +1 -0
  41. package/drag-drop/drag-drop-engine.d.ts.map +1 -1
  42. package/drag-drop/drag-drop-engine.js +8 -8
  43. package/drag-drop/drag-drop-engine.js.map +1 -1
  44. package/engines/editing/cell-editor-engine.js +1 -1
  45. package/engines/editing/cell-editor-engine.js.map +1 -1
  46. package/index.d.ts +6 -3
  47. package/index.d.ts.map +1 -1
  48. package/index.js +3 -1
  49. package/index.js.map +1 -1
  50. package/package.json +1 -1
  51. package/photon-ai/index.d.ts +2 -0
  52. package/photon-ai/index.d.ts.map +1 -1
  53. package/photon-ai/index.js +2 -0
  54. package/photon-ai/index.js.map +1 -1
  55. package/photon-ai/photon-ai-panel.d.ts +40 -0
  56. package/photon-ai/photon-ai-panel.d.ts.map +1 -1
  57. package/photon-ai/photon-ai-panel.js +163 -8
  58. package/photon-ai/photon-ai-panel.js.map +1 -1
  59. package/photon-ai/photon-ai-service.d.ts +38 -1
  60. package/photon-ai/photon-ai-service.d.ts.map +1 -1
  61. package/photon-ai/photon-ai-service.js +72 -1
  62. package/photon-ai/photon-ai-service.js.map +1 -1
  63. package/photon-ai/provider/ai-provider.types.d.ts +174 -0
  64. package/photon-ai/provider/ai-provider.types.d.ts.map +1 -0
  65. package/photon-ai/provider/ai-provider.types.js +42 -0
  66. package/photon-ai/provider/ai-provider.types.js.map +1 -0
  67. package/photon-ai/provider/command-normalizer.d.ts +36 -0
  68. package/photon-ai/provider/command-normalizer.d.ts.map +1 -0
  69. package/photon-ai/provider/command-normalizer.js +120 -0
  70. package/photon-ai/provider/command-normalizer.js.map +1 -0
  71. package/photon-ai/provider/grid-context-builder.d.ts +37 -0
  72. package/photon-ai/provider/grid-context-builder.d.ts.map +1 -0
  73. package/photon-ai/provider/grid-context-builder.js +96 -0
  74. package/photon-ai/provider/grid-context-builder.js.map +1 -0
  75. package/photon-ai/provider/http-ai-provider.d.ts +42 -0
  76. package/photon-ai/provider/http-ai-provider.d.ts.map +1 -0
  77. package/photon-ai/provider/http-ai-provider.js +125 -0
  78. package/photon-ai/provider/http-ai-provider.js.map +1 -0
  79. package/photon-ai/provider/index.d.ts +30 -0
  80. package/photon-ai/provider/index.d.ts.map +1 -0
  81. package/photon-ai/provider/index.js +42 -0
  82. package/photon-ai/provider/index.js.map +1 -0
  83. package/photon-ai/provider/presets.d.ts +29 -0
  84. package/photon-ai/provider/presets.d.ts.map +1 -0
  85. package/photon-ai/provider/presets.js +110 -0
  86. package/photon-ai/provider/presets.js.map +1 -0
  87. package/photon-ai/provider/response-parsing.d.ts +22 -0
  88. package/photon-ai/provider/response-parsing.d.ts.map +1 -0
  89. package/photon-ai/provider/response-parsing.js +79 -0
  90. package/photon-ai/provider/response-parsing.js.map +1 -0
  91. package/photon-ai/provider/system-prompt.d.ts +26 -0
  92. package/photon-ai/provider/system-prompt.d.ts.map +1 -0
  93. package/photon-ai/provider/system-prompt.js +82 -0
  94. package/photon-ai/provider/system-prompt.js.map +1 -0
  95. package/photon-grid.min.js +497 -56
  96. package/renderer/body-renderer.d.ts.map +1 -1
  97. package/renderer/body-renderer.js +34 -9
  98. package/renderer/body-renderer.js.map +1 -1
  99. package/renderer/column-chooser.d.ts +82 -0
  100. package/renderer/column-chooser.d.ts.map +1 -0
  101. package/renderer/column-chooser.js +335 -0
  102. package/renderer/column-chooser.js.map +1 -0
  103. package/renderer/column-menu.d.ts.map +1 -1
  104. package/renderer/column-menu.js +32 -20
  105. package/renderer/column-menu.js.map +1 -1
  106. package/renderer/column-style-manager.d.ts +17 -0
  107. package/renderer/column-style-manager.d.ts.map +1 -1
  108. package/renderer/column-style-manager.js +28 -0
  109. package/renderer/column-style-manager.js.map +1 -1
  110. package/renderer/detail-row-renderer.d.ts.map +1 -1
  111. package/renderer/detail-row-renderer.js +8 -6
  112. package/renderer/detail-row-renderer.js.map +1 -1
  113. package/renderer/grid-renderer.d.ts +10 -0
  114. package/renderer/grid-renderer.d.ts.map +1 -1
  115. package/renderer/grid-renderer.js +45 -7
  116. package/renderer/grid-renderer.js.map +1 -1
  117. package/renderer/group-drop-zone.js +14 -14
  118. package/renderer/group-drop-zone.js.map +1 -1
  119. package/renderer/header-renderer.d.ts +65 -0
  120. package/renderer/header-renderer.d.ts.map +1 -1
  121. package/renderer/header-renderer.js +347 -49
  122. package/renderer/header-renderer.js.map +1 -1
  123. package/renderer/row-animator.js +3 -3
  124. package/renderer/row-drag-renderer.js +6 -6
  125. package/renderer/row-drag-renderer.js.map +1 -1
  126. package/renderer/scroll-controller.d.ts +40 -0
  127. package/renderer/scroll-controller.d.ts.map +1 -1
  128. package/renderer/scroll-controller.js +184 -0
  129. package/renderer/scroll-controller.js.map +1 -1
  130. package/styles/base/column-chooser.css.d.ts +13 -0
  131. package/styles/base/column-chooser.css.d.ts.map +1 -0
  132. package/styles/base/column-chooser.css.js +241 -0
  133. package/styles/base/column-chooser.css.js.map +1 -0
  134. package/styles/base/column-context-menu.css.d.ts +1 -1
  135. package/styles/base/column-context-menu.css.d.ts.map +1 -1
  136. package/styles/base/column-context-menu.css.js +10 -0
  137. package/styles/base/column-context-menu.css.js.map +1 -1
  138. package/styles/base/filter.css.d.ts +1 -1
  139. package/styles/base/filter.css.js +1 -1
  140. package/styles/base/header.css.d.ts +1 -1
  141. package/styles/base/header.css.d.ts.map +1 -1
  142. package/styles/base/header.css.js +19 -0
  143. package/styles/base/header.css.js.map +1 -1
  144. package/styles/base/photon-ai.css.d.ts +1 -1
  145. package/styles/base/photon-ai.css.d.ts.map +1 -1
  146. package/styles/base/photon-ai.css.js +65 -0
  147. package/styles/base/photon-ai.css.js.map +1 -1
  148. package/styles/base/scrollbars.css.d.ts +1 -1
  149. package/styles/base/scrollbars.css.d.ts.map +1 -1
  150. package/styles/base/scrollbars.css.js +50 -4
  151. package/styles/base/scrollbars.css.js.map +1 -1
  152. package/styles/base/touch.css.d.ts +23 -0
  153. package/styles/base/touch.css.d.ts.map +1 -0
  154. package/styles/base/touch.css.js +85 -0
  155. package/styles/base/touch.css.js.map +1 -0
  156. package/styles/base-styles.d.ts.map +1 -1
  157. package/styles/base-styles.js +4 -0
  158. package/styles/base-styles.js.map +1 -1
  159. package/styles/themes/theme-dark.d.ts +1 -1
  160. package/styles/themes/theme-dark.d.ts.map +1 -1
  161. package/styles/themes/theme-dark.js +3 -0
  162. package/styles/themes/theme-dark.js.map +1 -1
  163. package/types/column.types.d.ts +36 -0
  164. package/types/column.types.d.ts.map +1 -1
  165. package/types/grid.types.d.ts +3 -2
  166. package/types/grid.types.d.ts.map +1 -1
  167. package/types/photon-ai.types.d.ts +125 -5
  168. package/types/photon-ai.types.d.ts.map +1 -1
  169. package/types/photon-ai.types.js +18 -1
  170. package/types/photon-ai.types.js.map +1 -1
@@ -0,0 +1,125 @@
1
+ import { PhotonAIProviderType } from '../../types/photon-ai.types';
2
+ import { getPreset } from './presets';
3
+ import { PhotonAIErrorKind, PhotonAIProviderError, } from './ai-provider.types';
4
+ /** Default request deadline. */
5
+ const DEFAULT_TIMEOUT_MS = 30000;
6
+ /**
7
+ * The single, provider-agnostic {@link PhotonAIProvider}. It is driven entirely
8
+ * by a consumer-supplied {@link PhotonAIProviderConfig}: pick a hosted
9
+ * {@link PhotonAIProviderType} for out-of-the-box defaults (endpoint, model,
10
+ * auth, wire format), or override any field — up to and including the full
11
+ * request/response wire format via `requestTransformer`/`responseTransformer` —
12
+ * to talk to any JSON HTTP model endpoint.
13
+ *
14
+ * Uses the native `fetch` API only (no SDK), so it runs in every browser Photon
15
+ * Grid supports. The API key is read from config at request time and applied
16
+ * with the provider's auth scheme; it is never hard-coded, cached, or logged.
17
+ * Every failure mode — HTTP errors, rate limits, auth problems, safety blocks,
18
+ * timeouts, and malformed JSON — surfaces as a categorized
19
+ * {@link PhotonAIProviderError}.
20
+ */
21
+ export class HttpAIProvider {
22
+ constructor(config) {
23
+ this.type = config.type ?? PhotonAIProviderType.Gemini;
24
+ this.preset = getPreset(this.type);
25
+ // A Custom provider ships no defaults — it must be fully specified.
26
+ if (!this.preset) {
27
+ if (!config.apiUrl || !config.requestTransformer || !config.responseTransformer) {
28
+ throw new PhotonAIProviderError(PhotonAIErrorKind.Http, 'A custom Photon AI provider requires apiUrl, requestTransformer, and responseTransformer.');
29
+ }
30
+ }
31
+ this.apiKey = config.apiKey?.trim() || undefined;
32
+ this.apiUrl = config.apiUrl?.trim() || this.preset?.defaultApiUrl || '';
33
+ this.model = config.model?.trim() || this.preset?.defaultModel || '';
34
+ this.headers = { ...(config.headers ?? {}) };
35
+ this.temperature = config.temperature ?? 0;
36
+ this.timeoutMs = config.requestTimeoutMs ?? DEFAULT_TIMEOUT_MS;
37
+ // Consumer transformers win; otherwise fall back to the preset's. The
38
+ // Custom-provider guard above guarantees both exist when there's no preset.
39
+ this.transformRequest = config.requestTransformer ?? this.preset.transformRequest;
40
+ this.transformResponse = config.responseTransformer ?? this.preset.transformResponse;
41
+ }
42
+ async generate(request) {
43
+ const neutral = {
44
+ systemInstruction: request.systemInstruction,
45
+ userCommand: request.userCommand,
46
+ gridContext: request.gridContext,
47
+ model: this.model,
48
+ temperature: this.temperature,
49
+ };
50
+ const body = this.transformRequest(neutral);
51
+ const url = this.buildUrl();
52
+ const headers = this.buildHeaders();
53
+ const response = await this.fetchWithTimeout(url, headers, body, request.signal);
54
+ const payload = await this.parseHttpResponse(response);
55
+ return this.transformResponse(payload);
56
+ }
57
+ /** Resolves the final URL (auth-in-query for Gemini, plain otherwise). */
58
+ buildUrl() {
59
+ if (this.preset)
60
+ return this.preset.buildUrl(this.apiUrl, this.model, this.apiKey);
61
+ return this.apiUrl;
62
+ }
63
+ /** Merges Content-Type + provider auth headers + consumer headers (consumer wins). */
64
+ buildHeaders() {
65
+ const auth = this.preset ? this.preset.buildHeaders(this.apiKey) : {};
66
+ return { 'Content-Type': 'application/json', ...auth, ...this.headers };
67
+ }
68
+ /** POSTs the request as JSON, enforcing the configured timeout via `AbortController`. */
69
+ async fetchWithTimeout(url, headers, body, external) {
70
+ const controller = new AbortController();
71
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
72
+ const onExternalAbort = () => controller.abort();
73
+ external?.addEventListener('abort', onExternalAbort, { once: true });
74
+ try {
75
+ return await fetch(url, { method: 'POST', headers, body: JSON.stringify(body), signal: controller.signal });
76
+ }
77
+ catch (err) {
78
+ if (external?.aborted) {
79
+ throw new PhotonAIProviderError(PhotonAIErrorKind.Network, 'Photon AI request was cancelled.');
80
+ }
81
+ if (controller.signal.aborted) {
82
+ throw new PhotonAIProviderError(PhotonAIErrorKind.Timeout, `The model did not respond within ${this.timeoutMs / 1000}s. Please try again.`);
83
+ }
84
+ const detail = err instanceof Error ? err.message : String(err);
85
+ throw new PhotonAIProviderError(PhotonAIErrorKind.Network, `Couldn't reach the model provider: ${detail}`);
86
+ }
87
+ finally {
88
+ clearTimeout(timer);
89
+ external?.removeEventListener('abort', onExternalAbort);
90
+ }
91
+ }
92
+ /** Validates the HTTP status, mapping known failure statuses (auth, rate-limit) to categorized errors, and returns the parsed JSON body. */
93
+ async parseHttpResponse(response) {
94
+ if (response.ok) {
95
+ try {
96
+ return await response.json();
97
+ }
98
+ catch {
99
+ throw new PhotonAIProviderError(PhotonAIErrorKind.InvalidResponse, 'The model provider returned a response that was not valid JSON.');
100
+ }
101
+ }
102
+ const message = await this.readErrorMessage(response);
103
+ const suffix = message ? ` ${message}` : '';
104
+ if (response.status === 429) {
105
+ throw new PhotonAIProviderError(PhotonAIErrorKind.RateLimit, `Rate limit reached. Please wait a moment and try again.${suffix}`, 429);
106
+ }
107
+ if (response.status === 401 || response.status === 403) {
108
+ throw new PhotonAIProviderError(PhotonAIErrorKind.Auth, `The model provider rejected the API key (HTTP ${response.status}).${suffix}`, response.status);
109
+ }
110
+ throw new PhotonAIProviderError(PhotonAIErrorKind.Http, `The model provider request failed (HTTP ${response.status}).${suffix}`, response.status);
111
+ }
112
+ /** Best-effort extraction of a provider error message from a non-2xx body (`{ error: { message } }` or `{ error: "..." }`). */
113
+ async readErrorMessage(response) {
114
+ try {
115
+ const payload = (await response.json());
116
+ if (typeof payload.error === 'string')
117
+ return payload.error.trim();
118
+ return payload.error?.message?.trim() ?? '';
119
+ }
120
+ catch {
121
+ return '';
122
+ }
123
+ }
124
+ }
125
+ //# sourceMappingURL=http-ai-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-ai-provider.js","sourceRoot":"","sources":["../../../src/photon-ai/provider/http-ai-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { PhotonAIProviderConfig } from '../../types/photon-ai.types';
2
+ import type { PhotonAIProvider } from './ai-provider.types';
3
+ export type { PhotonAIProvider, PhotonAIProviderRequest, PhotonAIRequest, PhotonAIResponse, PhotonAIGeneration, PhotonAIAction, PhotonGridContext, PhotonAIColumnContext, PhotonAICapability, PhotonAIGridState, PhotonAISortState, PhotonAIFilterState, } from './ai-provider.types';
4
+ export { PhotonAIErrorKind, PhotonAIProviderError, describeProviderError } from './ai-provider.types';
5
+ export { HttpAIProvider } from './http-ai-provider';
6
+ export { GridContextBuilder } from './grid-context-builder';
7
+ export { CommandNormalizer } from './command-normalizer';
8
+ export { buildSystemInstruction, serializeGridContext } from './system-prompt';
9
+ export { getPreset, coerceGeneration, parseGenerationText, type ProviderPreset } from './presets';
10
+ export { buildUserPromptText, normalizeActions } from './response-parsing';
11
+ /**
12
+ * Instantiates the {@link PhotonAIProvider} described by a
13
+ * {@link PhotonAIProviderConfig}. Returns `null` when no *usable* provider can
14
+ * be built — this is the signal for
15
+ * {@link import('../photon-ai-service').PhotonAIService} to stay in its default
16
+ * deterministic mode rather than fail. Configuring a provider is always
17
+ * strictly additive: a missing key or an incomplete custom setup silently
18
+ * keeps the offline pipeline.
19
+ *
20
+ * "Usable" means:
21
+ * - a hosted provider (Gemini/OpenAI/Anthropic) with an API key, or auth
22
+ * supplied via `headers`; or
23
+ * - a {@link PhotonAIProviderType.Custom} provider with an endpoint and both
24
+ * transformers.
25
+ *
26
+ * Every provider type routes through the single {@link HttpAIProvider}; adding a
27
+ * new hosted provider is just a new preset, not a new class.
28
+ */
29
+ export declare function createAIProvider(config: PhotonAIProviderConfig | undefined): PhotonAIProvider | null;
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/photon-ai/provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAG1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACtG,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3E;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,SAAS,GAAG,gBAAgB,GAAG,IAAI,CAapG"}
@@ -0,0 +1,42 @@
1
+ import { PhotonAIProviderType } from '../../types/photon-ai.types';
2
+ import { HttpAIProvider } from './http-ai-provider';
3
+ export { PhotonAIErrorKind, PhotonAIProviderError, describeProviderError } from './ai-provider.types';
4
+ export { HttpAIProvider } from './http-ai-provider';
5
+ export { GridContextBuilder } from './grid-context-builder';
6
+ export { CommandNormalizer } from './command-normalizer';
7
+ export { buildSystemInstruction, serializeGridContext } from './system-prompt';
8
+ export { getPreset, coerceGeneration, parseGenerationText } from './presets';
9
+ export { buildUserPromptText, normalizeActions } from './response-parsing';
10
+ /**
11
+ * Instantiates the {@link PhotonAIProvider} described by a
12
+ * {@link PhotonAIProviderConfig}. Returns `null` when no *usable* provider can
13
+ * be built — this is the signal for
14
+ * {@link import('../photon-ai-service').PhotonAIService} to stay in its default
15
+ * deterministic mode rather than fail. Configuring a provider is always
16
+ * strictly additive: a missing key or an incomplete custom setup silently
17
+ * keeps the offline pipeline.
18
+ *
19
+ * "Usable" means:
20
+ * - a hosted provider (Gemini/OpenAI/Anthropic) with an API key, or auth
21
+ * supplied via `headers`; or
22
+ * - a {@link PhotonAIProviderType.Custom} provider with an endpoint and both
23
+ * transformers.
24
+ *
25
+ * Every provider type routes through the single {@link HttpAIProvider}; adding a
26
+ * new hosted provider is just a new preset, not a new class.
27
+ */
28
+ export function createAIProvider(config) {
29
+ if (!config)
30
+ return null;
31
+ const type = config.type ?? PhotonAIProviderType.Gemini;
32
+ if (type === PhotonAIProviderType.Custom) {
33
+ if (!config.apiUrl || !config.requestTransformer || !config.responseTransformer)
34
+ return null;
35
+ }
36
+ else if (!config.apiKey?.trim() && !config.headers) {
37
+ // A hosted provider with no way to authenticate — fall back to deterministic.
38
+ return null;
39
+ }
40
+ return new HttpAIProvider(config);
41
+ }
42
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/photon-ai/provider/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAiBpD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACtG,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,mBAAmB,EAAuB,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAA0C;IACzE,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,oBAAoB,CAAC,MAAM,CAAC;IAExD,IAAI,IAAI,KAAK,oBAAoB,CAAC,MAAM,EAAE,CAAC;QACzC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,kBAAkB,IAAI,CAAC,MAAM,CAAC,mBAAmB;YAAE,OAAO,IAAI,CAAC;IAC/F,CAAC;SAAM,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACrD,8EAA8E;QAC9E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { PhotonAIProviderType } from '../../types/photon-ai.types';
2
+ import { type PhotonAIRequest, type PhotonAIResponse } from './ai-provider.types';
3
+ import { coerceGeneration, parseGenerationText } from './response-parsing';
4
+ /**
5
+ * A built-in provider preset: everything Photon AI needs to talk to a hosted
6
+ * LLM out of the box — default endpoint + model, how to place auth, and the
7
+ * request/response wire transformers. A consumer overrides any of these
8
+ * through {@link import('../../types/photon-ai.types').PhotonAIProviderConfig},
9
+ * so a preset is only the *default* wiring, never a hard requirement.
10
+ */
11
+ export interface ProviderPreset {
12
+ /** Default REST endpoint. May contain a `{model}` placeholder (Gemini). */
13
+ readonly defaultApiUrl: string;
14
+ /** Default model id for this provider. */
15
+ readonly defaultModel: string;
16
+ /** Builds the final request URL from the resolved endpoint, model, and key. */
17
+ buildUrl(apiUrl: string, model: string, apiKey: string | undefined): string;
18
+ /** Builds provider auth/headers from the key. Merged *under* consumer `headers`. */
19
+ buildHeaders(apiKey: string | undefined): Record<string, string>;
20
+ /** Default request-body transformer (overridable via config). */
21
+ transformRequest(request: PhotonAIRequest): unknown;
22
+ /** Default response parser (overridable via config). */
23
+ transformResponse(response: unknown): PhotonAIResponse;
24
+ }
25
+ /** The preset for a provider type, or `null` for {@link PhotonAIProviderType.Custom}. */
26
+ export declare function getPreset(type: PhotonAIProviderType): ProviderPreset | null;
27
+ /** Re-exported so a consumer's custom `responseTransformer` can reuse Photon AI's validated JSON→response coercion. */
28
+ export { coerceGeneration, parseGenerationText };
29
+ //# sourceMappingURL=presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../../src/photon-ai/provider/presets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAuB,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEhG;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,0CAA0C;IAC1C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IAC5E,oFAAoF;IACpF,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjE,iEAAiE;IACjE,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC;IACpD,wDAAwD;IACxD,iBAAiB,CAAC,QAAQ,EAAE,OAAO,GAAG,gBAAgB,CAAC;CACxD;AA8GD,yFAAyF;AACzF,wBAAgB,SAAS,CAAC,IAAI,EAAE,oBAAoB,GAAG,cAAc,GAAG,IAAI,CAE3E;AAED,uHAAuH;AACvH,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,CAAC"}
@@ -0,0 +1,110 @@
1
+ import { PhotonAIProviderType } from '../../types/photon-ai.types';
2
+ import { PhotonAIErrorKind, PhotonAIProviderError, } from './ai-provider.types';
3
+ import { buildUserPromptText, coerceGeneration, parseGenerationText } from './response-parsing';
4
+ /** Substitutes `{model}` and appends `key=` to a URL, respecting any existing query string. */
5
+ function geminiUrl(apiUrl, model, apiKey) {
6
+ const withModel = apiUrl.replace('{model}', encodeURIComponent(model));
7
+ if (!apiKey)
8
+ return withModel;
9
+ const separator = withModel.includes('?') ? '&' : '?';
10
+ return `${withModel}${separator}key=${encodeURIComponent(apiKey)}`;
11
+ }
12
+ /** Reads a nested text field out of an arbitrary parsed JSON body via a path of keys/indices. Returns '' if any hop is missing. */
13
+ function readText(source, path) {
14
+ let current = source;
15
+ for (const key of path) {
16
+ if (current == null)
17
+ return '';
18
+ current = current[key];
19
+ }
20
+ return typeof current === 'string' ? current : '';
21
+ }
22
+ const GEMINI_PRESET = {
23
+ defaultApiUrl: 'https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent',
24
+ defaultModel: 'gemini-2.5-flash',
25
+ buildUrl: geminiUrl,
26
+ buildHeaders: () => ({}),
27
+ transformRequest: (request) => ({
28
+ systemInstruction: { parts: [{ text: request.systemInstruction }] },
29
+ contents: [{ role: 'user', parts: [{ text: buildUserPromptText(request) }] }],
30
+ generationConfig: {
31
+ // Forces Gemini to always return a parseable JSON object.
32
+ responseMimeType: 'application/json',
33
+ temperature: request.temperature,
34
+ },
35
+ }),
36
+ transformResponse: (response) => {
37
+ const payload = response;
38
+ if (payload.promptFeedback?.blockReason) {
39
+ throw new PhotonAIProviderError(PhotonAIErrorKind.Blocked, `Gemini blocked the request (${payload.promptFeedback.blockReason}).`);
40
+ }
41
+ const candidate = payload.candidates?.[0];
42
+ if (!candidate) {
43
+ throw new PhotonAIProviderError(PhotonAIErrorKind.Blocked, 'Gemini returned no answer for that request.');
44
+ }
45
+ const text = candidate.content?.parts?.map((p) => p.text ?? '').join('') ?? '';
46
+ return parseGenerationText(text);
47
+ },
48
+ };
49
+ const OPENAI_PRESET = {
50
+ defaultApiUrl: 'https://api.openai.com/v1/chat/completions',
51
+ defaultModel: 'gpt-4o-mini',
52
+ buildUrl: (apiUrl) => apiUrl,
53
+ buildHeaders: (apiKey) => {
54
+ const headers = {};
55
+ if (apiKey)
56
+ headers.Authorization = `Bearer ${apiKey}`;
57
+ return headers;
58
+ },
59
+ transformRequest: (request) => ({
60
+ model: request.model,
61
+ temperature: request.temperature,
62
+ // Forces a JSON object back (system instruction already mentions JSON, as OpenAI requires).
63
+ response_format: { type: 'json_object' },
64
+ messages: [
65
+ { role: 'system', content: request.systemInstruction },
66
+ { role: 'user', content: buildUserPromptText(request) },
67
+ ],
68
+ }),
69
+ transformResponse: (response) => parseGenerationText(readText(response, ['choices', 0, 'message', 'content'])),
70
+ };
71
+ const ANTHROPIC_PRESET = {
72
+ defaultApiUrl: 'https://api.anthropic.com/v1/messages',
73
+ defaultModel: 'claude-haiku-4-5-20251001',
74
+ buildUrl: (apiUrl) => apiUrl,
75
+ buildHeaders: (apiKey) => {
76
+ const headers = {
77
+ 'anthropic-version': '2023-06-01',
78
+ // Required for calling the Anthropic API directly from a browser.
79
+ 'anthropic-dangerous-direct-browser-access': 'true',
80
+ };
81
+ if (apiKey)
82
+ headers['x-api-key'] = apiKey;
83
+ return headers;
84
+ },
85
+ transformRequest: (request) => ({
86
+ model: request.model,
87
+ max_tokens: 1024,
88
+ temperature: request.temperature,
89
+ system: request.systemInstruction,
90
+ messages: [{ role: 'user', content: buildUserPromptText(request) }],
91
+ }),
92
+ transformResponse: (response) => parseGenerationText(readText(response, ['content', 0, 'text'])),
93
+ };
94
+ /**
95
+ * Built-in presets by provider type. {@link PhotonAIProviderType.Custom} has no
96
+ * preset — a custom setup must supply its endpoint and both transformers.
97
+ */
98
+ const PRESETS = {
99
+ [PhotonAIProviderType.Gemini]: GEMINI_PRESET,
100
+ [PhotonAIProviderType.OpenAI]: OPENAI_PRESET,
101
+ [PhotonAIProviderType.Anthropic]: ANTHROPIC_PRESET,
102
+ [PhotonAIProviderType.Custom]: null,
103
+ };
104
+ /** The preset for a provider type, or `null` for {@link PhotonAIProviderType.Custom}. */
105
+ export function getPreset(type) {
106
+ return PRESETS[type] ?? null;
107
+ }
108
+ /** Re-exported so a consumer's custom `responseTransformer` can reuse Photon AI's validated JSON→response coercion. */
109
+ export { coerceGeneration, parseGenerationText };
110
+ //# sourceMappingURL=presets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.js","sourceRoot":"","sources":["../../../src/photon-ai/provider/presets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { type PhotonAIAction, type PhotonAIRequest, type PhotonAIResponse } from './ai-provider.types';
2
+ /**
3
+ * Provider-agnostic helpers for turning a model's raw text/JSON into a
4
+ * validated {@link PhotonAIResponse}, and for composing the user turn. Shared
5
+ * by every built-in provider preset so the JSON-recovery and validation logic
6
+ * lives in exactly one place regardless of which API produced the text.
7
+ */
8
+ /** The prompt text for the user turn: serialized grid context followed by the command. Reused by every preset. */
9
+ export declare function buildUserPromptText(request: PhotonAIRequest): string;
10
+ /**
11
+ * Parses the model's JSON *text* into a {@link PhotonAIResponse}. Tolerant of
12
+ * stray characters around the JSON object (some models wrap it), and validates
13
+ * that the result carries at least an action or a reply.
14
+ */
15
+ export declare function parseGenerationText(text: string): PhotonAIResponse;
16
+ /** Validates and normalizes an already-parsed JSON value into a {@link PhotonAIResponse}. Used by response transformers that receive an object. */
17
+ export declare function coerceGeneration(parsed: unknown): PhotonAIResponse;
18
+ /** Coerces the raw `actions` field into a validated, well-typed array — dropping any malformed entries. */
19
+ export declare function normalizeActions(raw: unknown): readonly PhotonAIAction[];
20
+ /** Last-ditch recovery: extract the first balanced `{...}` object from noisy model text. Returns `undefined` when none parses. */
21
+ export declare function tryRecoverJsonObject(text: string): unknown;
22
+ //# sourceMappingURL=response-parsing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-parsing.d.ts","sourceRoot":"","sources":["../../../src/photon-ai/provider/response-parsing.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAC;AAE7B;;;;;GAKG;AAEH,kHAAkH;AAClH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAoBlE;AAED,mJAAmJ;AACnJ,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,gBAAgB,CAiBlE;AAED,2GAA2G;AAC3G,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,cAAc,EAAE,CAcxE;AAED,kIAAkI;AAClI,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAS1D"}
@@ -0,0 +1,79 @@
1
+ import { serializeGridContext } from './system-prompt';
2
+ import { PhotonAIErrorKind, PhotonAIProviderError, } from './ai-provider.types';
3
+ /**
4
+ * Provider-agnostic helpers for turning a model's raw text/JSON into a
5
+ * validated {@link PhotonAIResponse}, and for composing the user turn. Shared
6
+ * by every built-in provider preset so the JSON-recovery and validation logic
7
+ * lives in exactly one place regardless of which API produced the text.
8
+ */
9
+ /** The prompt text for the user turn: serialized grid context followed by the command. Reused by every preset. */
10
+ export function buildUserPromptText(request) {
11
+ return `${serializeGridContext(request.gridContext)}\n\nUSER COMMAND:\n${request.userCommand}`;
12
+ }
13
+ /**
14
+ * Parses the model's JSON *text* into a {@link PhotonAIResponse}. Tolerant of
15
+ * stray characters around the JSON object (some models wrap it), and validates
16
+ * that the result carries at least an action or a reply.
17
+ */
18
+ export function parseGenerationText(text) {
19
+ const trimmed = text.trim();
20
+ if (!trimmed) {
21
+ throw new PhotonAIProviderError(PhotonAIErrorKind.InvalidResponse, 'The model returned an empty response.');
22
+ }
23
+ let parsed;
24
+ try {
25
+ parsed = JSON.parse(trimmed);
26
+ }
27
+ catch {
28
+ parsed = tryRecoverJsonObject(trimmed);
29
+ if (parsed === undefined) {
30
+ throw new PhotonAIProviderError(PhotonAIErrorKind.InvalidResponse, 'The model returned malformed JSON that could not be parsed.');
31
+ }
32
+ }
33
+ return coerceGeneration(parsed);
34
+ }
35
+ /** Validates and normalizes an already-parsed JSON value into a {@link PhotonAIResponse}. Used by response transformers that receive an object. */
36
+ export function coerceGeneration(parsed) {
37
+ if (typeof parsed !== 'object' || parsed === null) {
38
+ throw new PhotonAIProviderError(PhotonAIErrorKind.InvalidResponse, 'The model response was not a JSON object.');
39
+ }
40
+ const record = parsed;
41
+ const actions = normalizeActions(record.actions);
42
+ const reply = typeof record.reply === 'string' ? record.reply.trim() : '';
43
+ if (actions.length === 0 && !reply) {
44
+ throw new PhotonAIProviderError(PhotonAIErrorKind.InvalidResponse, 'The model response contained neither an action nor a reply.');
45
+ }
46
+ return { actions, reply };
47
+ }
48
+ /** Coerces the raw `actions` field into a validated, well-typed array — dropping any malformed entries. */
49
+ export function normalizeActions(raw) {
50
+ if (!Array.isArray(raw))
51
+ return [];
52
+ const actions = [];
53
+ for (const entry of raw) {
54
+ if (typeof entry !== 'object' || entry === null)
55
+ continue;
56
+ const record = entry;
57
+ if (typeof record.type !== 'string' || !record.type)
58
+ continue;
59
+ const params = typeof record.params === 'object' && record.params !== null
60
+ ? record.params
61
+ : {};
62
+ actions.push({ type: record.type, params });
63
+ }
64
+ return actions;
65
+ }
66
+ /** Last-ditch recovery: extract the first balanced `{...}` object from noisy model text. Returns `undefined` when none parses. */
67
+ export function tryRecoverJsonObject(text) {
68
+ const start = text.indexOf('{');
69
+ const end = text.lastIndexOf('}');
70
+ if (start < 0 || end <= start)
71
+ return undefined;
72
+ try {
73
+ return JSON.parse(text.slice(start, end + 1));
74
+ }
75
+ catch {
76
+ return undefined;
77
+ }
78
+ }
79
+ //# sourceMappingURL=response-parsing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-parsing.js","sourceRoot":"","sources":["../../../src/photon-ai/provider/response-parsing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EACL,iBAAiB,EACjB,qBAAqB,GAItB,MAAM,qBAAqB,CAAC;AAE7B;;;;;GAKG;AAEH,kHAAkH;AAClH,MAAM,UAAU,mBAAmB,CAAC,OAAwB;IAC1D,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,WAAW,CAAC,sBAAsB,OAAO,CAAC,WAAW,EAAE,CAAC;AACjG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,qBAAqB,CAAC,iBAAiB,CAAC,eAAe,EAAE,uCAAuC,CAAC,CAAC;IAC9G,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,qBAAqB,CAC7B,iBAAiB,CAAC,eAAe,EACjC,6DAA6D,CAC9D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAClC,CAAC;AAED,mJAAmJ;AACnJ,MAAM,UAAU,gBAAgB,CAAC,MAAe;IAC9C,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAClD,MAAM,IAAI,qBAAqB,CAAC,iBAAiB,CAAC,eAAe,EAAE,2CAA2C,CAAC,CAAC;IAClH,CAAC;IAED,MAAM,MAAM,GAAG,MAAiC,CAAC;IACjD,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAE1E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACnC,MAAM,IAAI,qBAAqB,CAC7B,iBAAiB,CAAC,eAAe,EACjC,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC1D,MAAM,MAAM,GAAG,KAAgC,CAAC;QAChD,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI;YAAE,SAAS;QAC9D,MAAM,MAAM,GACV,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI;YACzD,CAAC,CAAE,MAAM,CAAC,MAAkC;YAC5C,CAAC,CAAC,EAAE,CAAC;QACT,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,kIAAkI;AAClI,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,KAAK;QAAE,OAAO,SAAS,CAAC;IAChD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { PhotonGridContext } from './ai-provider.types';
2
+ /**
3
+ * Assembles the system instruction sent to a generative provider. This is the
4
+ * "rules of the game": the assistant's role, the **exact** JSON output
5
+ * contract, and the parameter conventions for turning an intent key into an
6
+ * executable command.
7
+ *
8
+ * It deliberately contains no grid-specific data (columns, live state) — that
9
+ * travels separately as the structured {@link PhotonGridContext} so it can be
10
+ * serialized once and reasoned over as data. Keeping the two apart means the
11
+ * instruction is stable and cache-friendly while the context changes per
12
+ * prompt.
13
+ *
14
+ * The output contract matches {@link import('./ai-provider.types').PhotonAIGeneration}
15
+ * exactly, so a well-formed response drops straight into the existing command
16
+ * pipeline with no bespoke parsing.
17
+ */
18
+ export declare function buildSystemInstruction(extraInstruction?: string): string;
19
+ /**
20
+ * Serializes the structured grid context into the compact, labelled block a
21
+ * provider sends alongside the user's command. Kept out of
22
+ * {@link buildSystemInstruction} so the two can be transmitted as distinct
23
+ * request parts (system rules vs. per-prompt data).
24
+ */
25
+ export declare function serializeGridContext(context: PhotonGridContext): string;
26
+ //# sourceMappingURL=system-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../../src/photon-ai/provider/system-prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAmDxE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAOvE"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Assembles the system instruction sent to a generative provider. This is the
3
+ * "rules of the game": the assistant's role, the **exact** JSON output
4
+ * contract, and the parameter conventions for turning an intent key into an
5
+ * executable command.
6
+ *
7
+ * It deliberately contains no grid-specific data (columns, live state) — that
8
+ * travels separately as the structured {@link PhotonGridContext} so it can be
9
+ * serialized once and reasoned over as data. Keeping the two apart means the
10
+ * instruction is stable and cache-friendly while the context changes per
11
+ * prompt.
12
+ *
13
+ * The output contract matches {@link import('./ai-provider.types').PhotonAIGeneration}
14
+ * exactly, so a well-formed response drops straight into the existing command
15
+ * pipeline with no bespoke parsing.
16
+ */
17
+ export function buildSystemInstruction(extraInstruction) {
18
+ const base = [
19
+ 'You are Photon AI, the built-in assistant for Photon Grid, an enterprise data grid.',
20
+ 'Your job: translate the user\'s natural-language request into concrete grid actions,',
21
+ 'and/or answer questions about the grid using the provided context.',
22
+ '',
23
+ 'You will be given, as JSON:',
24
+ ' • capabilities — the ONLY actions you may emit (each has a "type" key and a description),',
25
+ ' • columns — every column with its colId, header, data type, and flags,',
26
+ ' • state — the grid\'s current sort, filters, grouping, row/selection counts.',
27
+ '',
28
+ 'RESPOND WITH A SINGLE JSON OBJECT, and nothing else, matching this shape:',
29
+ '{',
30
+ ' "actions": [ { "type": <capability type>, "params": { ... } } ],',
31
+ ' "reply": <short, friendly, first-person sentence describing what you did or answering the question>',
32
+ '}',
33
+ '',
34
+ 'RULES:',
35
+ ' 1. "type" MUST be one of the capability "type" values verbatim. Never invent an action.',
36
+ ' 2. Reference columns ONLY by their exact "colId" from the columns list (not the header text).',
37
+ ' 3. A request may map to MULTIPLE actions (e.g. "hide id and sort by price desc") — list them in order.',
38
+ ' 4. If the request is a question about the grid (counts, current sort/filter, etc.), answer it in',
39
+ ' "reply" using the state/columns context and return "actions": []. Prefer the matching info',
40
+ ' capability (e.g. rowCount, sortInfo) when one exists.',
41
+ ' 5. If you cannot map the request to any capability, return "actions": [] and explain briefly in "reply".',
42
+ ' 6. Never include markdown, code fences, comments, or trailing text outside the JSON object.',
43
+ ' 7. Keep "reply" concise (one or two sentences) and never expose colIds or internal jargon to the user.',
44
+ '',
45
+ 'PARAMETER CONVENTIONS (params object per action type):',
46
+ ' • Single-column actions — sortAscending, sortDescending, hideColumn, showColumn, selectColumn,',
47
+ ' moveColumnToStart, moveColumnToEnd: { "colId": "<colId>" }',
48
+ ' • Multi-column actions — pinLeft, pinRight, unpin, groupBy: { "colIds": ["<colId>", ...] }',
49
+ ' • applyFilter: { "colId": "<colId>", "operator": <operator>, "value": <typed value>, "valueTo": <typed value, only for inRange> }',
50
+ ' • pinHalf: { "sides": ["left"] | ["right"] | ["left", "right"] }',
51
+ ' • Row-index actions — selectRow, expandRow, collapseRow: { "index": <1-based row number> }',
52
+ ' • Every other action (clearSort, clearFilters, unpinAll, hideAllColumns, showAllColumns, ungroup,',
53
+ ' expandAllGroups, collapseAllGroups, clearSelection, selectAllCells, copyAllCells, and all info',
54
+ ' actions): {}',
55
+ '',
56
+ 'FILTER OPERATORS by column type:',
57
+ ' • string: contains, notContains, equals, notEquals, startsWith, endsWith, blank, notBlank',
58
+ ' • number/currency/percentage: equals, notEquals, greaterThan, greaterThanOrEqual, lessThan,',
59
+ ' lessThanOrEqual, inRange (needs value + valueTo)',
60
+ ' • date/time: equals, before, after, inRange (needs value + valueTo). Dates as ISO strings "YYYY-MM-DD".',
61
+ ' • boolean: equals with value true/false',
62
+ ' • dropdown: equals with value taken from that column\'s "options" list',
63
+ ' Emit numbers as JSON numbers, booleans as JSON booleans, dates as ISO strings — never quote a number.',
64
+ ].join('\n');
65
+ const extra = extraInstruction?.trim();
66
+ return extra ? `${base}\n\nADDITIONAL INSTRUCTIONS:\n${extra}` : base;
67
+ }
68
+ /**
69
+ * Serializes the structured grid context into the compact, labelled block a
70
+ * provider sends alongside the user's command. Kept out of
71
+ * {@link buildSystemInstruction} so the two can be transmitted as distinct
72
+ * request parts (system rules vs. per-prompt data).
73
+ */
74
+ export function serializeGridContext(context) {
75
+ return [
76
+ 'GRID CONTEXT:',
77
+ `capabilities: ${JSON.stringify(context.capabilities)}`,
78
+ `columns: ${JSON.stringify(context.columns)}`,
79
+ `state: ${JSON.stringify(context.state)}`,
80
+ ].join('\n');
81
+ }
82
+ //# sourceMappingURL=system-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../../src/photon-ai/provider/system-prompt.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sBAAsB,CAAC,gBAAyB;IAC9D,MAAM,IAAI,GAAG;QACX,qFAAqF;QACrF,sFAAsF;QACtF,oEAAoE;QACpE,EAAE;QACF,6BAA6B;QAC7B,6FAA6F;QAC7F,0EAA0E;QAC1E,gFAAgF;QAChF,EAAE;QACF,2EAA2E;QAC3E,GAAG;QACH,oEAAoE;QACpE,uGAAuG;QACvG,GAAG;QACH,EAAE;QACF,QAAQ;QACR,2FAA2F;QAC3F,iGAAiG;QACjG,0GAA0G;QAC1G,oGAAoG;QACpG,iGAAiG;QACjG,4DAA4D;QAC5D,4GAA4G;QAC5G,+FAA+F;QAC/F,0GAA0G;QAC1G,EAAE;QACF,wDAAwD;QACxD,kGAAkG;QAClG,gEAAgE;QAChE,8FAA8F;QAC9F,qIAAqI;QACrI,oEAAoE;QACpE,8FAA8F;QAC9F,qGAAqG;QACrG,oGAAoG;QACpG,kBAAkB;QAClB,EAAE;QACF,kCAAkC;QAClC,6FAA6F;QAC7F,+FAA+F;QAC/F,sDAAsD;QACtD,2GAA2G;QAC3G,2CAA2C;QAC3C,0EAA0E;QAC1E,yGAAyG;KAC1G,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,KAAK,GAAG,gBAAgB,EAAE,IAAI,EAAE,CAAC;IACvC,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,iCAAiC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACxE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAA0B;IAC7D,OAAO;QACL,eAAe;QACf,iBAAiB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;QACvD,YAAY,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;QAC7C,UAAU,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;KAC1C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}