@elytracms/studio 0.0.100 → 0.0.102
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/convex/analytics-cost.test.ts +1 -1
- package/convex/asset-meta-patch.test.ts +7 -27
- package/convex/assets.ts +6 -41
- package/convex/cms.ts +2 -29
- package/convex/delivery.ts +2 -2
- package/convex/record-functions.ts +15 -82
- package/convex/redirects.ts +11 -116
- package/convex/schema.ts +4 -23
- package/convex/shared-capture.convex.test.ts +165 -0
- package/convex/triggers.ts +7 -14
- package/dist/components/ai/ai-chat-panel-lazy.js +7 -2
- package/dist/components/ai/ai-chat-panel-lazy.js.map +1 -1
- package/dist/components/ai/ai-chat-panel.js +8 -5
- package/dist/components/ai/ai-chat-panel.js.map +1 -1
- package/dist/components/ai/proposal-card.js +2 -1
- package/dist/components/ai/proposal-card.js.map +1 -1
- package/dist/components/ai/proposal-unfilled.d.ts +14 -0
- package/dist/components/ai/proposal-unfilled.js +33 -0
- package/dist/components/ai/proposal-unfilled.js.map +1 -0
- package/dist/components/ai/translate-document-action.js +8 -6
- package/dist/components/ai/translate-document-action.js.map +1 -1
- package/dist/components/ai/translate-skipped.js +1 -0
- package/dist/components/ai/translate-skipped.js.map +1 -1
- package/dist/components/app-views/studio-config.d.ts +12 -12
- package/dist/components/app-views/studio-config.js.map +1 -1
- package/dist/components/assets/asset-detail.js +1 -2
- package/dist/components/assets/asset-detail.js.map +1 -1
- package/dist/components/assets/asset-metadata.d.ts +2 -9
- package/dist/components/assets/asset-metadata.js +3 -10
- package/dist/components/assets/asset-metadata.js.map +1 -1
- package/dist/components/assets/asset-search.js +1 -1
- package/dist/components/assets/asset-search.js.map +1 -1
- package/dist/components/assets/asset-selection.js +2 -2
- package/dist/components/assets/asset-selection.js.map +1 -1
- package/dist/components/assets/assets-collection-view-source.d.ts +2 -3
- package/dist/components/assets/assets-collection-view-source.js +2 -3
- package/dist/components/assets/assets-collection-view-source.js.map +1 -1
- package/dist/components/builder/__fixtures__/reuse-race.d.ts +30 -0
- package/dist/components/builder/__fixtures__/reuse-race.js +77 -0
- package/dist/components/builder/__fixtures__/reuse-race.js.map +1 -0
- package/dist/components/builder/builder-store.d.ts +37 -1
- package/dist/components/builder/builder-store.js +21 -6
- package/dist/components/builder/builder-store.js.map +1 -1
- package/dist/components/builder/canvas-chrome-css.d.ts +1 -1
- package/dist/components/builder/canvas-chrome-css.js +1 -1
- package/dist/components/builder/canvas-chrome-css.js.map +1 -1
- package/dist/components/builder/canvas-chrome.d.ts +1 -1
- package/dist/components/builder/canvas-chrome.js +1 -1
- package/dist/components/builder/canvas-chrome.js.map +1 -1
- package/dist/components/builder/canvas-rebase.d.ts +4 -4
- package/dist/components/builder/canvas-rebase.js +3 -2
- package/dist/components/builder/canvas-rebase.js.map +1 -1
- package/dist/components/builder/canvas-render-context.d.ts +1 -1
- package/dist/components/builder/canvas-render-context.js +1 -1
- package/dist/components/builder/canvas-render-context.js.map +1 -1
- package/dist/components/builder/composition-field-editor-lazy.js +2 -1
- package/dist/components/builder/composition-field-editor-lazy.js.map +1 -1
- package/dist/components/builder/composition-field-editor.js +3 -3
- package/dist/components/builder/composition-field-editor.js.map +1 -1
- package/dist/components/builder/reuse-context.d.ts +9 -2
- package/dist/components/builder/reuse-context.js +46 -6
- package/dist/components/builder/reuse-context.js.map +1 -1
- package/dist/components/builder/reuse.d.ts +113 -70
- package/dist/components/builder/reuse.js +123 -108
- package/dist/components/builder/reuse.js.map +1 -1
- package/dist/components/cms/asset-field.js +1 -3
- package/dist/components/cms/asset-field.js.map +1 -1
- package/dist/components/cms/cell.d.ts +2 -2
- package/dist/components/cms/cell.js +8 -18
- package/dist/components/cms/cell.js.map +1 -1
- package/dist/components/cms/cms-store.d.ts +9 -1
- package/dist/components/cms/cms-store.js +1 -0
- package/dist/components/cms/cms-store.js.map +1 -1
- package/dist/components/cms/detail-editor.js +15 -14
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/field-control.js +13 -1
- package/dist/components/cms/field-control.js.map +1 -1
- package/dist/components/cms/prop-fields.js +1 -1
- package/dist/components/cms/prop-fields.js.map +1 -1
- package/dist/components/cms/rich-text/lazy.js +2 -1
- package/dist/components/cms/rich-text/lazy.js.map +1 -1
- package/dist/components/cms/rich-text/toolbar-state.d.ts +1 -1
- package/dist/components/cms/rich-text/toolbar-state.js +1 -1
- package/dist/components/cms/rich-text/toolbar-state.js.map +1 -1
- package/dist/components/cms/use-field-focus.js +3 -3
- package/dist/components/cms/use-field-focus.js.map +1 -1
- package/dist/components/cms/version-compare-lazy.js +2 -1
- package/dist/components/cms/version-compare-lazy.js.map +1 -1
- package/dist/components/components/components-index.js +1 -1
- package/dist/components/components/components-index.js.map +1 -1
- package/dist/components/deployment-setup-gate.d.ts +1 -1
- package/dist/components/deployment-setup-gate.js +1 -1
- package/dist/components/deployment-setup-gate.js.map +1 -1
- package/dist/components/load-failure.d.ts +62 -0
- package/dist/components/load-failure.js +110 -0
- package/dist/components/load-failure.js.map +1 -0
- package/dist/components/notifications/shell-findings.js +3 -3
- package/dist/components/notifications/shell-findings.js.map +1 -1
- package/dist/customization.d.ts +3 -3
- package/dist/customization.js.map +1 -1
- package/dist/lib/ai/apply-content.js +99 -28
- package/dist/lib/ai/apply-content.js.map +1 -1
- package/dist/lib/ai/chat-context.d.ts +77 -7
- package/dist/lib/ai/chat-context.js +139 -14
- package/dist/lib/ai/chat-context.js.map +1 -1
- package/dist/lib/ai/chat-state.d.ts +7 -1
- package/dist/lib/ai/chat-state.js.map +1 -1
- package/dist/lib/ai/constraints.d.ts +5 -0
- package/dist/lib/ai/constraints.js +21 -6
- package/dist/lib/ai/constraints.js.map +1 -1
- package/dist/lib/ai/fake-provider.d.ts +76 -26
- package/dist/lib/ai/fake-provider.js +210 -66
- package/dist/lib/ai/fake-provider.js.map +1 -1
- package/dist/lib/ai/index.d.ts +1 -0
- package/dist/lib/ai/index.js +1 -0
- package/dist/lib/ai/index.js.map +1 -1
- package/dist/lib/ai/keyless-assistant.d.ts +37 -0
- package/dist/lib/ai/keyless-assistant.js +193 -0
- package/dist/lib/ai/keyless-assistant.js.map +1 -0
- package/dist/lib/ai/knowledge.d.ts +9 -9
- package/dist/lib/ai/knowledge.js +22 -0
- package/dist/lib/ai/knowledge.js.map +1 -1
- package/dist/lib/ai/shape.d.ts +25 -2
- package/dist/lib/ai/shape.js +58 -7
- package/dist/lib/ai/shape.js.map +1 -1
- package/dist/lib/ai/tools.d.ts +18 -1
- package/dist/lib/ai/tools.js +74 -11
- package/dist/lib/ai/tools.js.map +1 -1
- package/dist/lib/ai/translate-document.d.ts +8 -1
- package/dist/lib/ai/translate-document.js +25 -9
- package/dist/lib/ai/translate-document.js.map +1 -1
- package/dist/lib/ai/types.d.ts +22 -7
- package/dist/lib/ai/types.js.map +1 -1
- package/dist/lib/ai/update-fields.js +13 -17
- package/dist/lib/ai/update-fields.js.map +1 -1
- package/dist/lib/ai/writer-form.d.ts +72 -3
- package/dist/lib/ai/writer-form.js +320 -42
- package/dist/lib/ai/writer-form.js.map +1 -1
- package/dist/lib/assets/upload.d.ts +1 -2
- package/dist/lib/assets/upload.js +1 -2
- package/dist/lib/assets/upload.js.map +1 -1
- package/dist/lib/auth-errors.d.ts +1 -1
- package/dist/lib/auth-errors.js +1 -1
- package/dist/lib/auth-errors.js.map +1 -1
- package/dist/lib/engine-version.d.ts +1 -1
- package/dist/lib/engine-version.js +1 -1
- package/dist/lib/engine-version.js.map +1 -1
- package/dist/lib/i18n/messages.de.d.ts +1 -1
- package/dist/lib/i18n/messages.de.js +32 -8
- package/dist/lib/i18n/messages.de.js.map +1 -1
- package/dist/lib/i18n/messages.en.d.ts +25 -3
- package/dist/lib/i18n/messages.en.js +40 -10
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/operations/cms-persistence.d.ts +28 -0
- package/dist/lib/operations/cms-persistence.js +55 -0
- package/dist/lib/operations/cms-persistence.js.map +1 -1
- package/dist/lib/persistence/convex-adapter.js +7 -2
- package/dist/lib/persistence/convex-adapter.js.map +1 -1
- package/dist/lib/workspace/index.d.ts +3 -3
- package/dist/lib/workspace/index.js +3 -3
- package/dist/lib/workspace/index.js.map +1 -1
- package/dist/router/navigate-once.d.ts +1 -1
- package/dist/router/navigate-once.js.map +1 -1
- package/dist/router/root.d.ts +3 -2
- package/dist/router/root.js +25 -4
- package/dist/router/root.js.map +1 -1
- package/package.json +3 -3
- package/convex/asset-alt-migration.test.ts +0 -127
- package/convex/redirect-migration.test.ts +0 -205
- package/convex/version-kind-stamping.test.ts +0 -118
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseCollectionCatalog, parseCurrentDocumentSection } from './chat-context.js';
|
|
1
2
|
/** Zero-usage report (the fake spends nothing). Shape = `LanguageModelV4Usage`. */
|
|
2
3
|
const FAKE_USAGE = {
|
|
3
4
|
inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },
|
|
@@ -32,24 +33,6 @@ function lastUserText(prompt) {
|
|
|
32
33
|
.join(' ')
|
|
33
34
|
.trim();
|
|
34
35
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Tool names with a RESULT in the CURRENT user turn (prompt suffix after the
|
|
37
|
-
* last user message) — the stateless stage detector for scripted flows.
|
|
38
|
-
*/
|
|
39
|
-
function toolResultNamesInCurrentTurn(prompt) {
|
|
40
|
-
const names = new Set();
|
|
41
|
-
for (const message of prompt.slice(lastUserIndex(prompt) + 1)) {
|
|
42
|
-
if (!Array.isArray(message.content))
|
|
43
|
-
continue;
|
|
44
|
-
for (const part of message.content) {
|
|
45
|
-
const candidate = part;
|
|
46
|
-
if (candidate.type === 'tool-result' && typeof candidate.toolName === 'string') {
|
|
47
|
-
names.add(candidate.toolName);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return names;
|
|
52
|
-
}
|
|
53
36
|
/** Provider-spec parts for one text-preamble + tool-call turn (finish `tool-calls`). */
|
|
54
37
|
function toolTurnParts(preamble, toolName, input, callId) {
|
|
55
38
|
const encoded = JSON.stringify(input);
|
|
@@ -156,10 +139,12 @@ export function createFakeChatModel(options = {}) {
|
|
|
156
139
|
},
|
|
157
140
|
};
|
|
158
141
|
}
|
|
159
|
-
/**
|
|
160
|
-
export const FAKE_CREATE_FLOW_ANSWER = '
|
|
161
|
-
/**
|
|
162
|
-
export const FAKE_UPDATE_FLOW_ANSWER = '
|
|
142
|
+
/** The closing sentence of a create that landed (EC-715: said only when one did). */
|
|
143
|
+
export const FAKE_CREATE_FLOW_ANSWER = 'Review the proposal below and apply it as a draft.';
|
|
144
|
+
/** The closing sentence of an update that landed (EC-378; EC-715: said only when one did). */
|
|
145
|
+
export const FAKE_UPDATE_FLOW_ANSWER = 'Review the proposed change below and apply it as a draft.';
|
|
146
|
+
/** What the keyless assistant says when the catalog offers nothing it may create in (EC-715). */
|
|
147
|
+
export const FAKE_NOTHING_CREATABLE_ANSWER = 'This project has no collection I can create a document in — singletons and the media library take no new documents.';
|
|
163
148
|
/** Default edit-request detector of the scripted assistant (EC-378). */
|
|
164
149
|
export const FAKE_UPDATE_PATTERN = /\b(change|update|edit|remove|replace|rewrite|fix|set)\b/i;
|
|
165
150
|
/**
|
|
@@ -197,78 +182,237 @@ export function fakeUpdateTargetFrom(userText, fallback) {
|
|
|
197
182
|
...(match[2] !== undefined && match[3] !== undefined ? { blockId: match[2], prop: match[3] } : {}),
|
|
198
183
|
};
|
|
199
184
|
}
|
|
185
|
+
/** The system prompt's text (the route folds the request's context sections into it). */
|
|
186
|
+
function systemText(prompt) {
|
|
187
|
+
return prompt
|
|
188
|
+
.filter((message) => message.role === 'system')
|
|
189
|
+
.map((message) => (typeof message.content === 'string' ? message.content : ''))
|
|
190
|
+
.join('\n\n');
|
|
191
|
+
}
|
|
192
|
+
/** How many user turns the prompt holds — the deterministic part of a per-turn tool-call id. */
|
|
193
|
+
function userTurnCount(prompt) {
|
|
194
|
+
return prompt.filter((message) => message.role === 'user').length;
|
|
195
|
+
}
|
|
196
|
+
/** The tool calls and tool results after the last user message, in order. */
|
|
197
|
+
function currentTurnToolParts(prompt) {
|
|
198
|
+
const calls = [];
|
|
199
|
+
const results = [];
|
|
200
|
+
for (const message of prompt.slice(lastUserIndex(prompt) + 1)) {
|
|
201
|
+
if (!Array.isArray(message.content))
|
|
202
|
+
continue;
|
|
203
|
+
for (const part of message.content) {
|
|
204
|
+
const candidate = part;
|
|
205
|
+
if (typeof candidate.toolCallId !== 'string' || typeof candidate.toolName !== 'string')
|
|
206
|
+
continue;
|
|
207
|
+
if (candidate.type === 'tool-call') {
|
|
208
|
+
let input = candidate.input;
|
|
209
|
+
if (typeof input === 'string') {
|
|
210
|
+
try {
|
|
211
|
+
input = JSON.parse(input);
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
input = undefined;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
calls.push({ toolCallId: candidate.toolCallId, toolName: candidate.toolName, input });
|
|
218
|
+
}
|
|
219
|
+
else if (candidate.type === 'tool-result') {
|
|
220
|
+
results.push({
|
|
221
|
+
toolCallId: candidate.toolCallId,
|
|
222
|
+
toolName: candidate.toolName,
|
|
223
|
+
output: (candidate.output ?? {}),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return { calls, results };
|
|
229
|
+
}
|
|
230
|
+
/** A tool result's error text, or `undefined` when the tool succeeded. */
|
|
231
|
+
function toolError(result) {
|
|
232
|
+
const output = result.output ?? {};
|
|
233
|
+
if (output.type === 'error-text')
|
|
234
|
+
return typeof output.value === 'string' ? output.value : 'the tool failed';
|
|
235
|
+
if (output.type === 'error-json')
|
|
236
|
+
return JSON.stringify(output.value);
|
|
237
|
+
if (output.type === 'execution-denied')
|
|
238
|
+
return 'the tool call was denied';
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
/** A successful tool result's JSON value (`{}` for anything else). */
|
|
242
|
+
function toolJson(result) {
|
|
243
|
+
const value = result.output?.type === 'json' ? result.output.value : undefined;
|
|
244
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value) ? value : {};
|
|
245
|
+
}
|
|
246
|
+
function escapeRegExp(text) {
|
|
247
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
248
|
+
}
|
|
249
|
+
/** Where the user's text first names a collection (its id or label, plural allowed), or -1. */
|
|
250
|
+
function namedAt(entry, text) {
|
|
251
|
+
const terms = [entry.id, ...(entry.label !== undefined ? [entry.label] : [])];
|
|
252
|
+
let best = -1;
|
|
253
|
+
for (const term of terms) {
|
|
254
|
+
const match = new RegExp(`\\b${escapeRegExp(term)}s?\\b`, 'i').exec(text);
|
|
255
|
+
if (match && (best < 0 || match.index < best))
|
|
256
|
+
best = match.index;
|
|
257
|
+
}
|
|
258
|
+
return best;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* The collection a keyless create targets (EC-715), read off the catalog the system prompt
|
|
262
|
+
* carries — never a hardcoded name: one the user's text NAMES (id or label; the earliest
|
|
263
|
+
* mention wins), else the collection of the document open in the editor, else the first
|
|
264
|
+
* creatable one. A singleton or the media library is never a create target.
|
|
265
|
+
*/
|
|
266
|
+
export function chooseCreateCollection(catalog, userText, openCollection) {
|
|
267
|
+
const creatable = catalog.filter((entry) => !entry.singleton && !entry.assetLibrary);
|
|
268
|
+
let named;
|
|
269
|
+
let namedIndex = -1;
|
|
270
|
+
for (const entry of creatable) {
|
|
271
|
+
const index = namedAt(entry, userText);
|
|
272
|
+
if (index >= 0 && (namedIndex < 0 || index < namedIndex)) {
|
|
273
|
+
named = entry;
|
|
274
|
+
namedIndex = index;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return named ?? creatable.find((entry) => entry.id === openCollection) ?? creatable[0];
|
|
278
|
+
}
|
|
279
|
+
/** A collection's name in an answer: its label, else its id. */
|
|
280
|
+
function collectionName(catalog, id) {
|
|
281
|
+
const entry = catalog.find((candidate) => candidate.id === id);
|
|
282
|
+
return entry?.label ?? (typeof id === 'string' ? id : 'document');
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* The create flow's answer, DERIVED from the `createDocument` result (EC-715): a refused
|
|
286
|
+
* create states the refusal, quoting the error; a proposal says what was drafted and which
|
|
287
|
+
* positions it left empty (`unfilled`). It used to say "Done" whatever the result said.
|
|
288
|
+
*/
|
|
289
|
+
export function fakeCreateAnswer(result, catalog, collection, successText) {
|
|
290
|
+
const name = collectionName(catalog, collection);
|
|
291
|
+
const error = toolError(result);
|
|
292
|
+
if (error !== undefined)
|
|
293
|
+
return `I could not draft the ${name}: ${error}`;
|
|
294
|
+
const output = toolJson(result);
|
|
295
|
+
if (output.status !== 'proposed')
|
|
296
|
+
return `The ${name} was not drafted.`;
|
|
297
|
+
if (successText !== undefined)
|
|
298
|
+
return successText;
|
|
299
|
+
const title = typeof output.title === 'string' ? ` "${output.title}"` : '';
|
|
300
|
+
const unfilled = Array.isArray(output.unfilled)
|
|
301
|
+
? output.unfilled.filter((entry) => typeof entry === 'string')
|
|
302
|
+
: [];
|
|
303
|
+
const skipped = unfilled.length > 0 ? ` Left empty: ${unfilled.join('; ')}.` : '';
|
|
304
|
+
return `I drafted a new ${name}${title}.${skipped} ${FAKE_CREATE_FLOW_ANSWER}`;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* The update flow's answer, DERIVED from the tool results (EC-715): a refused update states
|
|
308
|
+
* the refusal, quoting the error; a proposal names what changed.
|
|
309
|
+
*/
|
|
310
|
+
export function fakeUpdateAnswer(result, successText) {
|
|
311
|
+
const error = toolError(result);
|
|
312
|
+
if (error !== undefined)
|
|
313
|
+
return `I could not change it: ${error}`;
|
|
314
|
+
const output = toolJson(result);
|
|
315
|
+
if (output.status === 'no-change') {
|
|
316
|
+
return typeof output.note === 'string' ? output.note : 'There is nothing to change.';
|
|
317
|
+
}
|
|
318
|
+
if (output.status !== 'proposed')
|
|
319
|
+
return 'Nothing was changed.';
|
|
320
|
+
if (successText !== undefined)
|
|
321
|
+
return successText;
|
|
322
|
+
const changed = Array.isArray(output.changedFields)
|
|
323
|
+
? output.changedFields.filter((entry) => typeof entry === 'string')
|
|
324
|
+
: [];
|
|
325
|
+
return `I proposed a change to ${changed.length > 0 ? changed.join(', ') : 'the document'}. ${FAKE_UPDATE_FLOW_ANSWER}`;
|
|
326
|
+
}
|
|
200
327
|
/**
|
|
201
328
|
* A scripted, STATELESS fake chat model that drives the FULL create flow — and,
|
|
202
329
|
* for a user turn matching the update pattern, the EC-378 UPDATE flow — over the
|
|
203
330
|
* native loop (EC-334): keyless playground / CI exercise the whole client-tool
|
|
204
331
|
* round-trip deterministically. Stage is read from the CURRENT user turn's tool
|
|
205
|
-
* results (prompt suffix after the last user message), so every follow-up
|
|
206
|
-
* starts a fresh flow — multi-turn works without model state.
|
|
332
|
+
* calls and results (prompt suffix after the last user message), so every follow-up
|
|
333
|
+
* turn starts a fresh flow — multi-turn works without model state.
|
|
207
334
|
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
335
|
+
* EC-715: it reads THE PROJECT, never a hardcoded collection — the catalog and the open
|
|
336
|
+
* document arrive in the system prompt (the route has no data access; that prose is the only
|
|
337
|
+
* channel), read back by `parseCollectionCatalog` / `parseCurrentDocumentSection`. Every
|
|
338
|
+
* answer is derived from the tool results (a refusal is said, never "Done"), and every tool
|
|
339
|
+
* call id carries the user-turn number, so a second proposal never replaces the first card.
|
|
212
340
|
*
|
|
213
|
-
*
|
|
214
|
-
* 1.
|
|
215
|
-
* 2.
|
|
216
|
-
* 3.
|
|
217
|
-
*
|
|
341
|
+
* Create flow:
|
|
342
|
+
* 1. the target: {@link chooseCreateCollection} (none creatable → it says so);
|
|
343
|
+
* 2. each REQUIRED relation target not yet searched this turn → `searchDocuments`;
|
|
344
|
+
* 3. the target has an asset field (or `searchAssets`) and the library was not listed
|
|
345
|
+
* this turn → `listAssets({ query?: assetQuery })`;
|
|
346
|
+
* 4. → `createDocument({ collection, instruction: <last user text> })`;
|
|
347
|
+
* 5. a `createDocument` result → {@link fakeCreateAnswer}.
|
|
218
348
|
*
|
|
219
349
|
* Update flow (user text matches `updatePattern`, e.g. "Change the title to: X"):
|
|
220
350
|
* 1. no tool result yet → `getDocument({})` — target omitted on purpose:
|
|
221
351
|
* the executor resolves the document OPEN in the
|
|
222
352
|
* editor (the EC-378 current-document seam)
|
|
223
|
-
* 2. document read
|
|
353
|
+
* 2. document read → `updateFields({ changes: [{
|
|
224
354
|
* ...fakeUpdateTargetFrom(<text>, updateField),
|
|
225
355
|
* value: fakeUpdateValueFrom(<last user text>) }] })`
|
|
226
356
|
* — "Set the body to: ## Neu" drives a markdown
|
|
227
357
|
* rich-text update deterministically (EC-379);
|
|
228
358
|
* "Set the body component <id> <prop> to: X" one
|
|
229
|
-
* component prop at any depth (EC-593)
|
|
230
|
-
*
|
|
359
|
+
* component prop at any depth (EC-593); a refused read
|
|
360
|
+
* answers with the refusal instead
|
|
361
|
+
* 3. update result present → {@link fakeUpdateAnswer}.
|
|
231
362
|
*/
|
|
232
363
|
export function createFakeCreateFlowChatModel(options = {}) {
|
|
233
|
-
const searchCollection = options.searchCollection ?? 'author';
|
|
234
|
-
const createCollection = options.createCollection ?? 'post';
|
|
235
|
-
const searchAssets = options.searchAssets ?? false;
|
|
236
|
-
const answer = options.answerText ?? FAKE_CREATE_FLOW_ANSWER;
|
|
237
364
|
const updateField = options.updateField ?? 'title';
|
|
238
365
|
const updatePattern = options.updatePattern ?? FAKE_UPDATE_PATTERN;
|
|
239
|
-
const updateAnswer = options.updateAnswerText ?? FAKE_UPDATE_FLOW_ANSWER;
|
|
240
366
|
return createFakeChatModel({
|
|
241
367
|
modelId: options.modelId ?? 'fake-create-flow-model',
|
|
242
368
|
script: (callOptions) => {
|
|
243
|
-
const
|
|
244
|
-
const
|
|
369
|
+
const prompt = callOptions.prompt;
|
|
370
|
+
const turn = userTurnCount(prompt);
|
|
371
|
+
const { calls, results } = currentTurnToolParts(prompt);
|
|
372
|
+
const resultOf = (toolName) => results.find((result) => result.toolName === toolName);
|
|
373
|
+
const userText = lastUserText(prompt);
|
|
245
374
|
if (updatePattern.test(userText)) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
],
|
|
256
|
-
}, 'call-update-1');
|
|
375
|
+
const updated = resultOf('updateFields');
|
|
376
|
+
if (updated)
|
|
377
|
+
return answerTurnParts(fakeUpdateAnswer(updated, options.updateAnswerText));
|
|
378
|
+
const read = resultOf('getDocument');
|
|
379
|
+
if (read) {
|
|
380
|
+
const error = toolError(read);
|
|
381
|
+
if (error !== undefined)
|
|
382
|
+
return answerTurnParts(`I could not read the document: ${error}`);
|
|
383
|
+
return toolTurnParts('Proposing the change. ', 'updateFields', { changes: [{ ...fakeUpdateTargetFrom(userText, updateField), value: fakeUpdateValueFrom(userText) }] }, `call-update-${turn}`);
|
|
257
384
|
}
|
|
258
|
-
return toolTurnParts('Reading the document. ', 'getDocument', {},
|
|
385
|
+
return toolTurnParts('Reading the document. ', 'getDocument', {}, `call-get-${turn}`);
|
|
259
386
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
387
|
+
const system = systemText(prompt);
|
|
388
|
+
const catalog = parseCollectionCatalog(system);
|
|
389
|
+
const created = resultOf('createDocument');
|
|
390
|
+
if (created) {
|
|
391
|
+
const call = calls.find((candidate) => candidate.toolCallId === created.toolCallId);
|
|
392
|
+
const collection = call?.input?.collection;
|
|
393
|
+
return answerTurnParts(fakeCreateAnswer(created, catalog, collection, options.answerText));
|
|
394
|
+
}
|
|
395
|
+
const target = chooseCreateCollection(catalog, userText, parseCurrentDocumentSection(system)?.collection);
|
|
396
|
+
if (!target)
|
|
397
|
+
return answerTurnParts(FAKE_NOTHING_CREATABLE_ANSWER);
|
|
398
|
+
// EC-715: every REQUIRED relation target, once per turn (the blog kit's post needs its
|
|
399
|
+
// author) — searched in catalog order.
|
|
400
|
+
const answered = new Set(results.map((result) => result.toolCallId));
|
|
401
|
+
const searched = new Set(calls
|
|
402
|
+
.filter((call) => call.toolName === 'searchDocuments' && answered.has(call.toolCallId))
|
|
403
|
+
.map((call) => call.input?.collection));
|
|
404
|
+
const targets = [...new Set(target.relations.filter((relation) => relation.required).map((relation) => relation.target))];
|
|
405
|
+
const next = targets.findIndex((relationTarget) => !searched.has(relationTarget));
|
|
406
|
+
if (next >= 0) {
|
|
407
|
+
return toolTurnParts(FAKE_CHAT_PREAMBLE, 'searchDocuments', { collection: targets[next] }, `call-search-${turn}-${next + 1}`);
|
|
408
|
+
}
|
|
409
|
+
// EC-381 — search the media library before creating (a topically fitting, REAL asset
|
|
410
|
+
// fills the image field via the enum leash).
|
|
411
|
+
const searchAssets = options.searchAssets ?? target.assetFields.length > 0;
|
|
412
|
+
if (searchAssets && !resultOf('listAssets')) {
|
|
413
|
+
return toolTurnParts('Looking for a fitting image. ', 'listAssets', { ...(options.assetQuery ? { query: options.assetQuery } : {}) }, `call-assets-${turn}`);
|
|
270
414
|
}
|
|
271
|
-
return toolTurnParts(
|
|
415
|
+
return toolTurnParts('Drafting a proposal. ', 'createDocument', { collection: target.id, instruction: userText || 'Write a short document.' }, `call-create-${turn}`);
|
|
272
416
|
},
|
|
273
417
|
});
|
|
274
418
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-provider.js","sourceRoot":"","sources":["../../../src/lib/ai/fake-provider.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * FakeProvider (EC-331): a deterministic, fixture-driven {@link AiProvider} that\n * implements the same interface as the Anthropic provider, so playground / demo /\n * tests run the WHOLE loop (config gate → shape → generate → validate → repair →\n * patch) without a key. Determinism is a project principle: the same fixtures always\n * yield the same result. Imports no AI SDK at runtime — the `LanguageModelV4` spec\n * below is implemented STRUCTURALLY from type-only imports (erased at compile;\n * pinned in `bundle.test.ts`).\n *\n * For the repair loop, pass `objects: [invalidDoc, validDoc]` — the provider returns\n * them in call order (the last is reused once the script is exhausted). Or pass\n * `respond` to compute the object from the request.\n *\n * EC-334 adds {@link createFakeChatModel}: a scripted fake `LanguageModel` served by\n * the ROUTE's native chat branch, so the keyless playground / CI drive the FULL\n * `streamText` → SSE wire → client-tool loop. It is a STATELESS prompt-inspecting\n * responder (state read from the prompt, the FakeProvider trick): a prompt without a\n * tool result emits a tool call; a prompt carrying one streams a text answer.\n */\n// Type-only (erased): the fake implements the SDK's v4 model spec structurally.\nimport type { LanguageModel } from 'ai'\nimport type { AiProvider, AiProviderCapabilities, GenerateStructuredRequest } from './types'\n\n// --- Fake chat model (EC-334) -------------------------------------------------------\n\n/** The SDK's v4 language-model spec, extracted structurally from the type-only union. */\nexport type FakeLanguageModelV4 = Extract<LanguageModel, { specificationVersion: 'v4' }>\n\n/** The call options a fake chat model receives (`LanguageModelV4CallOptions`). */\nexport type FakeChatModelCallOptions = Parameters<FakeLanguageModelV4['doGenerate']>[0]\n\n/** One provider-spec stream part the fake emits (`LanguageModelV4StreamPart`). */\nexport type FakeChatModelStreamPart =\n Awaited<ReturnType<FakeLanguageModelV4['doStream']>>['stream'] extends ReadableStream<infer PART>\n ? PART\n : never\n\ntype FakeFinishPart = Extract<FakeChatModelStreamPart, { type: 'finish' }>\ntype FakeGenerateResult = Awaited<ReturnType<FakeLanguageModelV4['doGenerate']>>\n\n/** Zero-usage report (the fake spends nothing). Shape = `LanguageModelV4Usage`. */\nconst FAKE_USAGE: FakeFinishPart['usage'] = {\n inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },\n outputTokens: { total: 0, text: 0, reasoning: 0 },\n}\n\n/** Default preamble streamed before the scripted tool call. */\nexport const FAKE_CHAT_PREAMBLE = 'Let me look that up. '\n/** Default final answer streamed once the prompt carries a tool result. */\nexport const FAKE_CHAT_ANSWER = 'Found it — the tool result is in, and this is the answer.'\n\nexport interface FakeChatModelOptions {\n /** Model id reported to the SDK (default `fake-chat-model`). */\n modelId?: string\n /** Text streamed before the tool call on the first (tool-result-free) turn. */\n preambleText?: string\n /** The tool the first turn requests (default `searchDocuments`). */\n toolName?: string\n /** The tool-call input (default `{ collection: 'post' }`). */\n toolInput?: Record<string, unknown>\n /** The answer streamed word-by-word once the prompt carries a tool result. */\n answerText?: string\n /**\n * Full override: script the exact provider-spec stream parts for a call\n * (zero-based call index). The default prompt-inspecting behavior is skipped.\n */\n script?: (options: FakeChatModelCallOptions, callIndex: number) => FakeChatModelStreamPart[]\n}\n\n/** A fake chat model that also records the calls it received, for assertions. */\nexport type FakeChatModel = FakeLanguageModelV4 & {\n /** Every `doStream` / `doGenerate` call options received, in order. */\n readonly calls: FakeChatModelCallOptions[]\n}\n\n/** Does any prompt message carry a tool RESULT part? (The fake's only \"state\".) */\nfunction promptHasToolResult(prompt: FakeChatModelCallOptions['prompt']): boolean {\n return prompt.some(\n (message) =>\n Array.isArray(message.content) &&\n message.content.some(\n (part) => (part as { type?: unknown }).type === 'tool-result',\n ),\n )\n}\n\n/** Index of the LAST user message in the prompt (`-1` when none). */\nfunction lastUserIndex(prompt: FakeChatModelCallOptions['prompt']): number {\n for (let i = prompt.length - 1; i >= 0; i -= 1) {\n if (prompt[i]?.role === 'user') return i\n }\n return -1\n}\n\n/** The last user message's text (the fake's \"instruction\" source). */\nfunction lastUserText(prompt: FakeChatModelCallOptions['prompt']): string {\n const index = lastUserIndex(prompt)\n const message = prompt[index]\n if (!message || !Array.isArray(message.content)) return ''\n return message.content\n .filter((part): part is { type: 'text'; text: string } => (part as { type?: unknown }).type === 'text')\n .map((part) => part.text)\n .join(' ')\n .trim()\n}\n\n/**\n * Tool names with a RESULT in the CURRENT user turn (prompt suffix after the\n * last user message) — the stateless stage detector for scripted flows.\n */\nfunction toolResultNamesInCurrentTurn(prompt: FakeChatModelCallOptions['prompt']): Set<string> {\n const names = new Set<string>()\n for (const message of prompt.slice(lastUserIndex(prompt) + 1)) {\n if (!Array.isArray(message.content)) continue\n for (const part of message.content) {\n const candidate = part as { type?: unknown; toolName?: unknown }\n if (candidate.type === 'tool-result' && typeof candidate.toolName === 'string') {\n names.add(candidate.toolName)\n }\n }\n }\n return names\n}\n\n/** Provider-spec parts for one text-preamble + tool-call turn (finish `tool-calls`). */\nfunction toolTurnParts(\n preamble: string,\n toolName: string,\n input: Record<string, unknown>,\n callId: string,\n): FakeChatModelStreamPart[] {\n const encoded = JSON.stringify(input)\n return [\n { type: 'stream-start', warnings: [] },\n { type: 'text-start', id: 'text-1' },\n { type: 'text-delta', id: 'text-1', delta: preamble },\n { type: 'text-end', id: 'text-1' },\n { type: 'tool-input-start', id: callId, toolName },\n { type: 'tool-input-delta', id: callId, delta: encoded },\n { type: 'tool-input-end', id: callId },\n { type: 'tool-call', toolCallId: callId, toolName, input: encoded },\n {\n type: 'finish',\n usage: FAKE_USAGE,\n finishReason: { unified: 'tool-calls', raw: 'fake-tool-calls' },\n },\n ]\n}\n\n/** Provider-spec parts for a word-by-word streamed text answer (finish `stop`). */\nfunction answerTurnParts(answer: string): FakeChatModelStreamPart[] {\n return [\n { type: 'stream-start', warnings: [] },\n { type: 'text-start', id: 'text-1' },\n ...wordDeltas(answer).map(\n (delta): FakeChatModelStreamPart => ({ type: 'text-delta', id: 'text-1', delta }),\n ),\n { type: 'text-end', id: 'text-1' },\n { type: 'finish', usage: FAKE_USAGE, finishReason: { unified: 'stop', raw: 'fake-stop' } },\n ]\n}\n\n/** Split text into word deltas (trailing spaces preserved) for visible streaming. */\nfunction wordDeltas(text: string): string[] {\n const words = text.split(' ')\n return words.map((word, index) => (index < words.length - 1 ? `${word} ` : word))\n}\n\n/**\n * Build a scripted, stateless fake `LanguageModel` (the `LanguageModelV4` spec,\n * implemented structurally — zero SDK runtime import). Default behavior:\n * - prompt WITHOUT a tool result → preamble text, then a `tool-call` for\n * {@link FakeChatModelOptions.toolName} (finish reason `tool-calls`);\n * - prompt WITH a tool result → the answer text streamed word-by-word (`stop`).\n * Chunk shapes follow the v4 spec: `finishReason` is `{ unified, raw }`, tool chunks\n * are `tool-input-start/delta/end` + `tool-call`.\n */\nexport function createFakeChatModel(options: FakeChatModelOptions = {}): FakeChatModel {\n const preamble = options.preambleText ?? FAKE_CHAT_PREAMBLE\n const toolName = options.toolName ?? 'searchDocuments'\n const toolInput = options.toolInput ?? { collection: 'post' }\n const answer = options.answerText ?? FAKE_CHAT_ANSWER\n const calls: FakeChatModelCallOptions[] = []\n let callIndex = 0\n\n function partsFor(callOptions: FakeChatModelCallOptions): FakeChatModelStreamPart[] {\n if (options.script) return options.script(callOptions, callIndex)\n if (!promptHasToolResult(callOptions.prompt)) {\n return toolTurnParts(preamble, toolName, toolInput, 'call-1')\n }\n return answerTurnParts(answer)\n }\n\n /** Fold the scripted stream parts into a non-streaming `doGenerate` result. */\n function materialize(parts: FakeChatModelStreamPart[]): FakeGenerateResult {\n const content: FakeGenerateResult['content'] = []\n const textById = new Map<string, string>()\n let finishReason: FakeFinishPart['finishReason'] = { unified: 'stop', raw: 'fake-stop' }\n for (const part of parts) {\n if (part.type === 'text-delta') {\n textById.set(part.id, (textById.get(part.id) ?? '') + part.delta)\n } else if (part.type === 'tool-call') {\n content.push(part)\n } else if (part.type === 'finish') {\n finishReason = part.finishReason\n }\n }\n for (const text of textById.values()) content.unshift({ type: 'text', text })\n return { content, finishReason, usage: FAKE_USAGE, warnings: [] }\n }\n\n return {\n specificationVersion: 'v4',\n provider: 'fake',\n modelId: options.modelId ?? 'fake-chat-model',\n supportedUrls: {},\n calls,\n doGenerate(callOptions) {\n calls.push(callOptions)\n const parts = partsFor(callOptions)\n callIndex += 1\n return Promise.resolve(materialize(parts))\n },\n doStream(callOptions) {\n calls.push(callOptions)\n const parts = partsFor(callOptions)\n callIndex += 1\n return Promise.resolve({\n stream: new ReadableStream<FakeChatModelStreamPart>({\n start(controller) {\n for (const part of parts) controller.enqueue(part)\n controller.close()\n },\n }),\n })\n },\n }\n}\n\n// --- Fake create-flow chat model (EC-334 slice 2) -------------------------------------\n\nexport interface FakeCreateFlowChatModelOptions {\n /** Model id reported to the SDK (default `fake-create-flow-model`). */\n modelId?: string\n /** The collection the first stage searches (a relation target; default `author`). */\n searchCollection?: string\n /**\n * EC-381: when set, the create flow inserts a `listAssets` stage after the\n * relation search and before `createDocument`, so a collection with an image\n * field gets it filled from a REAL library asset (the enum leash). Optional\n * search text passed to `listAssets` (omit to list all).\n */\n searchAssets?: boolean\n /** Optional query passed to the scripted `listAssets` stage (EC-381). */\n assetQuery?: string\n /** The collection the terminal stage creates in (default `post`). */\n createCollection?: string\n /** The final answer streamed word-by-word after the proposal lands. */\n answerText?: string\n /**\n * EC-378: the field the scripted UPDATE flow changes (default `title`). A user\n * turn matching {@link FakeCreateFlowChatModelOptions.updatePattern} routes to\n * the update flow instead of the create flow.\n */\n updateField?: string\n /** Routes a user turn to the update flow (default {@link FAKE_UPDATE_PATTERN}). */\n updatePattern?: RegExp\n /** The final answer of the scripted update flow. */\n updateAnswerText?: string\n}\n\n/** Default final answer of the scripted create flow. */\nexport const FAKE_CREATE_FLOW_ANSWER =\n 'Done — review the proposal below and apply it as a draft.'\n\n/** Default final answer of the scripted update flow (EC-378). */\nexport const FAKE_UPDATE_FLOW_ANSWER =\n 'Done — review the proposed change below and apply it as a draft.'\n\n/** Default edit-request detector of the scripted assistant (EC-378). */\nexport const FAKE_UPDATE_PATTERN = /\\b(change|update|edit|remove|replace|rewrite|fix|set)\\b/i\n\n/**\n * The scripted update flow's new value for the target field: the text after the\n * FIRST colon when present (`Set the title to: New Title` → `New Title`), else\n * the whole user text — deterministic either way. First (not last) colon so a\n * markdown body value may itself contain colons (EC-379).\n */\nexport function fakeUpdateValueFrom(userText: string): string {\n const colon = userText.indexOf(':')\n const value = colon >= 0 ? userText.slice(colon + 1) : userText\n return value.trim() || 'Updated by the assistant'\n}\n\n/**\n * The scripted update flow's TARGET FIELD (EC-379): `set/change/update the\n * <field> to: …` names it (so the playground can drive a markdown-authored\n * rich-text update deterministically, e.g. `Set the body to: ## Neu`); anything\n * else falls back to the configured default field.\n */\nexport function fakeUpdateFieldFrom(userText: string, fallback: string): string {\n return fakeUpdateTargetFrom(userText, fallback).field\n}\n\n/**\n * The scripted update flow's full TARGET (EC-593): a field, or one component prop\n * inside it — `set the <field> component <id> <prop> to: …` names a component by its\n * node id at any depth (`Set the body component p-home-quote-note value to: Hi`), so the\n * keyless playground can drive a component-prop edit through the one converter.\n */\nexport function fakeUpdateTargetFrom(\n userText: string,\n fallback: string,\n): { field: string; blockId?: string; prop?: string } {\n const match =\n /\\b(?:set|change|update)\\s+the\\s+([A-Za-z]\\w*)(?:\\s+component\\s+([\\w-]+)\\s+([A-Za-z]\\w*))?\\s+to\\s*:/i.exec(\n userText,\n )\n if (!match) return { field: fallback }\n return {\n field: match[1]!,\n ...(match[2] !== undefined && match[3] !== undefined ? { blockId: match[2], prop: match[3] } : {}),\n }\n}\n\n/**\n * A scripted, STATELESS fake chat model that drives the FULL create flow — and,\n * for a user turn matching the update pattern, the EC-378 UPDATE flow — over the\n * native loop (EC-334): keyless playground / CI exercise the whole client-tool\n * round-trip deterministically. Stage is read from the CURRENT user turn's tool\n * results (prompt suffix after the last user message), so every follow-up turn\n * starts a fresh flow — multi-turn works without model state.\n *\n * Create flow (default):\n * 1. no tool result yet → `searchDocuments({ collection: searchCollection })`\n * 2. search result, no create → `createDocument({ collection, instruction: <last user text> })`\n * 3. create result present → the answer text, word by word.\n *\n * With `searchAssets` (EC-381), a `listAssets` stage is inserted between 1 and 2:\n * 1. no tool result yet → `searchDocuments({ collection: searchCollection })`\n * 2. search done, no listAssets → `listAssets({ query?: assetQuery })`\n * 3. listAssets done, no create → `createDocument({ collection, instruction })`\n * 4. create result present → the answer text, word by word.\n *\n * Update flow (user text matches `updatePattern`, e.g. \"Change the title to: X\"):\n * 1. no tool result yet → `getDocument({})` — target omitted on purpose:\n * the executor resolves the document OPEN in the\n * editor (the EC-378 current-document seam)\n * 2. document read, no update → `updateFields({ changes: [{\n * ...fakeUpdateTargetFrom(<text>, updateField),\n * value: fakeUpdateValueFrom(<last user text>) }] })`\n * — \"Set the body to: ## Neu\" drives a markdown\n * rich-text update deterministically (EC-379);\n * \"Set the body component <id> <prop> to: X\" one\n * component prop at any depth (EC-593)\n * 3. update result present → the update answer, word by word.\n */\nexport function createFakeCreateFlowChatModel(\n options: FakeCreateFlowChatModelOptions = {},\n): FakeChatModel {\n const searchCollection = options.searchCollection ?? 'author'\n const createCollection = options.createCollection ?? 'post'\n const searchAssets = options.searchAssets ?? false\n const answer = options.answerText ?? FAKE_CREATE_FLOW_ANSWER\n const updateField = options.updateField ?? 'title'\n const updatePattern = options.updatePattern ?? FAKE_UPDATE_PATTERN\n const updateAnswer = options.updateAnswerText ?? FAKE_UPDATE_FLOW_ANSWER\n return createFakeChatModel({\n modelId: options.modelId ?? 'fake-create-flow-model',\n script: (callOptions) => {\n const done = toolResultNamesInCurrentTurn(callOptions.prompt)\n const userText = lastUserText(callOptions.prompt)\n if (updatePattern.test(userText)) {\n if (done.has('updateFields')) return answerTurnParts(updateAnswer)\n if (done.has('getDocument')) {\n return toolTurnParts(\n 'Proposing the change. ',\n 'updateFields',\n {\n changes: [\n {\n ...fakeUpdateTargetFrom(userText, updateField),\n value: fakeUpdateValueFrom(userText),\n },\n ],\n },\n 'call-update-1',\n )\n }\n return toolTurnParts('Reading the document. ', 'getDocument', {}, 'call-get-1')\n }\n if (done.has('createDocument')) return answerTurnParts(answer)\n if (done.has('searchDocuments')) {\n // EC-381 — search the media library before creating (a topically fitting,\n // REAL asset fills the image field via the enum leash).\n if (searchAssets && !done.has('listAssets')) {\n return toolTurnParts(\n 'Looking for a fitting image. ',\n 'listAssets',\n { ...(options.assetQuery ? { query: options.assetQuery } : {}) },\n 'call-assets-1',\n )\n }\n const instruction = userText || 'Write a short document.'\n return toolTurnParts(\n 'Drafting a proposal. ',\n 'createDocument',\n { collection: createCollection, instruction },\n 'call-create-1',\n )\n }\n return toolTurnParts(\n FAKE_CHAT_PREAMBLE,\n 'searchDocuments',\n { collection: searchCollection },\n 'call-search-1',\n )\n },\n })\n}\n\n// --- Fake provider ------------------------------------------------------------------\n\nexport interface FakeProviderOptions {\n /** Provider id (default `fake`). */\n id?: string\n /** Model id recorded in provenance (default `fake-model`). */\n model?: string\n /** Reported capabilities (default: both true). Set to test the capability gate. */\n capabilities?: AiProviderCapabilities\n /** Scripted objects returned in call order; the last entry is reused when exhausted. */\n objects?: unknown[]\n /** Compute the object from the request + zero-based call index (overrides `objects`). */\n respond?: (request: GenerateStructuredRequest, callIndex: number) => unknown\n /** The scripted chat model `languageModel()` serves (default {@link createFakeChatModel}). */\n chatModel?: FakeChatModel\n}\n\n/** A FakeProvider that also records the requests it received, for assertions. */\nexport interface FakeProvider extends AiProvider {\n /** Every `generateStructured` request received, in order. */\n readonly calls: GenerateStructuredRequest[]\n /** The scripted fake chat model behind `languageModel()` (records its calls). */\n readonly chatModel: FakeChatModel\n}\n\nexport function createFakeProvider(options: FakeProviderOptions = {}): FakeProvider {\n const calls: GenerateStructuredRequest[] = []\n const objects = options.objects ?? []\n const chatModel = options.chatModel ?? createFakeChatModel()\n let index = 0\n\n return {\n id: options.id ?? 'fake',\n model: options.model ?? 'fake-model',\n calls,\n chatModel,\n capabilities: (): AiProviderCapabilities =>\n options.capabilities ?? { toolCalling: true, structuredOutput: true },\n\n languageModel: () => Promise.resolve(chatModel),\n\n generateStructured(request) {\n calls.push(request)\n const callIndex = index\n index += 1\n const object = options.respond\n ? options.respond(request, callIndex)\n : objects.length > 0\n ? objects[Math.min(callIndex, objects.length - 1)]\n : {}\n return Promise.resolve({ object, usage: { inputTokens: 0, outputTokens: 0 } })\n },\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"fake-provider.js","sourceRoot":"","sources":["../../../src/lib/ai/fake-provider.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * FakeProvider (EC-331): a deterministic, fixture-driven {@link AiProvider} that\n * implements the same interface as the Anthropic provider, so playground / demo /\n * tests run the WHOLE loop (config gate → shape → generate → validate → repair →\n * patch) without a key. Determinism is a project principle: the same fixtures always\n * yield the same result. Imports no AI SDK at runtime — the `LanguageModelV4` spec\n * below is implemented STRUCTURALLY from type-only imports (erased at compile;\n * pinned in `bundle.test.ts`).\n *\n * For the repair loop, pass `objects: [invalidDoc, validDoc]` — the provider returns\n * them in call order (the last is reused once the script is exhausted). Or pass\n * `respond` to compute the object from the request.\n *\n * EC-334 adds {@link createFakeChatModel}: a scripted fake `LanguageModel` served by\n * the ROUTE's native chat branch, so the keyless playground / CI drive the FULL\n * `streamText` → SSE wire → client-tool loop. It is a STATELESS prompt-inspecting\n * responder (state read from the prompt, the FakeProvider trick): a prompt without a\n * tool result emits a tool call; a prompt carrying one streams a text answer.\n */\n// Type-only (erased): the fake implements the SDK's v4 model spec structurally.\nimport type { LanguageModel } from 'ai'\nimport { parseCollectionCatalog, parseCurrentDocumentSection } from './chat-context'\nimport type { CatalogCollection } from './chat-context'\nimport type { AiProvider, AiProviderCapabilities, GenerateStructuredRequest } from './types'\n\n// --- Fake chat model (EC-334) -------------------------------------------------------\n\n/** The SDK's v4 language-model spec, extracted structurally from the type-only union. */\nexport type FakeLanguageModelV4 = Extract<LanguageModel, { specificationVersion: 'v4' }>\n\n/** The call options a fake chat model receives (`LanguageModelV4CallOptions`). */\nexport type FakeChatModelCallOptions = Parameters<FakeLanguageModelV4['doGenerate']>[0]\n\n/** One provider-spec stream part the fake emits (`LanguageModelV4StreamPart`). */\nexport type FakeChatModelStreamPart =\n Awaited<ReturnType<FakeLanguageModelV4['doStream']>>['stream'] extends ReadableStream<infer PART>\n ? PART\n : never\n\ntype FakeFinishPart = Extract<FakeChatModelStreamPart, { type: 'finish' }>\ntype FakeGenerateResult = Awaited<ReturnType<FakeLanguageModelV4['doGenerate']>>\n\n/** Zero-usage report (the fake spends nothing). Shape = `LanguageModelV4Usage`. */\nconst FAKE_USAGE: FakeFinishPart['usage'] = {\n inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },\n outputTokens: { total: 0, text: 0, reasoning: 0 },\n}\n\n/** Default preamble streamed before the scripted tool call. */\nexport const FAKE_CHAT_PREAMBLE = 'Let me look that up. '\n/** Default final answer streamed once the prompt carries a tool result. */\nexport const FAKE_CHAT_ANSWER = 'Found it — the tool result is in, and this is the answer.'\n\nexport interface FakeChatModelOptions {\n /** Model id reported to the SDK (default `fake-chat-model`). */\n modelId?: string\n /** Text streamed before the tool call on the first (tool-result-free) turn. */\n preambleText?: string\n /** The tool the first turn requests (default `searchDocuments`). */\n toolName?: string\n /** The tool-call input (default `{ collection: 'post' }`). */\n toolInput?: Record<string, unknown>\n /** The answer streamed word-by-word once the prompt carries a tool result. */\n answerText?: string\n /**\n * Full override: script the exact provider-spec stream parts for a call\n * (zero-based call index). The default prompt-inspecting behavior is skipped.\n */\n script?: (options: FakeChatModelCallOptions, callIndex: number) => FakeChatModelStreamPart[]\n}\n\n/** A fake chat model that also records the calls it received, for assertions. */\nexport type FakeChatModel = FakeLanguageModelV4 & {\n /** Every `doStream` / `doGenerate` call options received, in order. */\n readonly calls: FakeChatModelCallOptions[]\n}\n\n/** Does any prompt message carry a tool RESULT part? (The fake's only \"state\".) */\nfunction promptHasToolResult(prompt: FakeChatModelCallOptions['prompt']): boolean {\n return prompt.some(\n (message) =>\n Array.isArray(message.content) &&\n message.content.some(\n (part) => (part as { type?: unknown }).type === 'tool-result',\n ),\n )\n}\n\n/** Index of the LAST user message in the prompt (`-1` when none). */\nfunction lastUserIndex(prompt: FakeChatModelCallOptions['prompt']): number {\n for (let i = prompt.length - 1; i >= 0; i -= 1) {\n if (prompt[i]?.role === 'user') return i\n }\n return -1\n}\n\n/** The last user message's text (the fake's \"instruction\" source). */\nfunction lastUserText(prompt: FakeChatModelCallOptions['prompt']): string {\n const index = lastUserIndex(prompt)\n const message = prompt[index]\n if (!message || !Array.isArray(message.content)) return ''\n return message.content\n .filter((part): part is { type: 'text'; text: string } => (part as { type?: unknown }).type === 'text')\n .map((part) => part.text)\n .join(' ')\n .trim()\n}\n\n/** Provider-spec parts for one text-preamble + tool-call turn (finish `tool-calls`). */\nfunction toolTurnParts(\n preamble: string,\n toolName: string,\n input: Record<string, unknown>,\n callId: string,\n): FakeChatModelStreamPart[] {\n const encoded = JSON.stringify(input)\n return [\n { type: 'stream-start', warnings: [] },\n { type: 'text-start', id: 'text-1' },\n { type: 'text-delta', id: 'text-1', delta: preamble },\n { type: 'text-end', id: 'text-1' },\n { type: 'tool-input-start', id: callId, toolName },\n { type: 'tool-input-delta', id: callId, delta: encoded },\n { type: 'tool-input-end', id: callId },\n { type: 'tool-call', toolCallId: callId, toolName, input: encoded },\n {\n type: 'finish',\n usage: FAKE_USAGE,\n finishReason: { unified: 'tool-calls', raw: 'fake-tool-calls' },\n },\n ]\n}\n\n/** Provider-spec parts for a word-by-word streamed text answer (finish `stop`). */\nfunction answerTurnParts(answer: string): FakeChatModelStreamPart[] {\n return [\n { type: 'stream-start', warnings: [] },\n { type: 'text-start', id: 'text-1' },\n ...wordDeltas(answer).map(\n (delta): FakeChatModelStreamPart => ({ type: 'text-delta', id: 'text-1', delta }),\n ),\n { type: 'text-end', id: 'text-1' },\n { type: 'finish', usage: FAKE_USAGE, finishReason: { unified: 'stop', raw: 'fake-stop' } },\n ]\n}\n\n/** Split text into word deltas (trailing spaces preserved) for visible streaming. */\nfunction wordDeltas(text: string): string[] {\n const words = text.split(' ')\n return words.map((word, index) => (index < words.length - 1 ? `${word} ` : word))\n}\n\n/**\n * Build a scripted, stateless fake `LanguageModel` (the `LanguageModelV4` spec,\n * implemented structurally — zero SDK runtime import). Default behavior:\n * - prompt WITHOUT a tool result → preamble text, then a `tool-call` for\n * {@link FakeChatModelOptions.toolName} (finish reason `tool-calls`);\n * - prompt WITH a tool result → the answer text streamed word-by-word (`stop`).\n * Chunk shapes follow the v4 spec: `finishReason` is `{ unified, raw }`, tool chunks\n * are `tool-input-start/delta/end` + `tool-call`.\n */\nexport function createFakeChatModel(options: FakeChatModelOptions = {}): FakeChatModel {\n const preamble = options.preambleText ?? FAKE_CHAT_PREAMBLE\n const toolName = options.toolName ?? 'searchDocuments'\n const toolInput = options.toolInput ?? { collection: 'post' }\n const answer = options.answerText ?? FAKE_CHAT_ANSWER\n const calls: FakeChatModelCallOptions[] = []\n let callIndex = 0\n\n function partsFor(callOptions: FakeChatModelCallOptions): FakeChatModelStreamPart[] {\n if (options.script) return options.script(callOptions, callIndex)\n if (!promptHasToolResult(callOptions.prompt)) {\n return toolTurnParts(preamble, toolName, toolInput, 'call-1')\n }\n return answerTurnParts(answer)\n }\n\n /** Fold the scripted stream parts into a non-streaming `doGenerate` result. */\n function materialize(parts: FakeChatModelStreamPart[]): FakeGenerateResult {\n const content: FakeGenerateResult['content'] = []\n const textById = new Map<string, string>()\n let finishReason: FakeFinishPart['finishReason'] = { unified: 'stop', raw: 'fake-stop' }\n for (const part of parts) {\n if (part.type === 'text-delta') {\n textById.set(part.id, (textById.get(part.id) ?? '') + part.delta)\n } else if (part.type === 'tool-call') {\n content.push(part)\n } else if (part.type === 'finish') {\n finishReason = part.finishReason\n }\n }\n for (const text of textById.values()) content.unshift({ type: 'text', text })\n return { content, finishReason, usage: FAKE_USAGE, warnings: [] }\n }\n\n return {\n specificationVersion: 'v4',\n provider: 'fake',\n modelId: options.modelId ?? 'fake-chat-model',\n supportedUrls: {},\n calls,\n doGenerate(callOptions) {\n calls.push(callOptions)\n const parts = partsFor(callOptions)\n callIndex += 1\n return Promise.resolve(materialize(parts))\n },\n doStream(callOptions) {\n calls.push(callOptions)\n const parts = partsFor(callOptions)\n callIndex += 1\n return Promise.resolve({\n stream: new ReadableStream<FakeChatModelStreamPart>({\n start(controller) {\n for (const part of parts) controller.enqueue(part)\n controller.close()\n },\n }),\n })\n },\n }\n}\n\n// --- Fake create-flow chat model (EC-334 slice 2, reads the project since EC-715) -------\n\nexport interface FakeCreateFlowChatModelOptions {\n /** Model id reported to the SDK (default `fake-create-flow-model`). */\n modelId?: string\n /**\n * @deprecated EC-715 — never read. The keyless assistant reads the project's catalog from\n * the system prompt and searches every REQUIRED relation target of the collection it\n * creates in. Kept so a project scaffolded before the change still type-checks; delete it.\n */\n searchCollection?: string\n /**\n * EC-381: whether the create flow inserts a `listAssets` stage before `createDocument`,\n * so an image field is filled from a REAL library asset (the enum leash). Default\n * (EC-715): when the collection it creates in has an asset field.\n */\n searchAssets?: boolean\n /** Optional query passed to the scripted `listAssets` stage (EC-381). */\n assetQuery?: string\n /**\n * @deprecated EC-715 — never read. The collection is chosen from the catalog: one the\n * user's text names, else the open document's, else the first creatable one. Kept so a\n * project scaffolded before the change still type-checks; delete it.\n */\n createCollection?: string\n /**\n * The answer streamed after a proposal LANDED (default: what was drafted, then\n * {@link FAKE_CREATE_FLOW_ANSWER}). A refused create always answers with the refusal.\n */\n answerText?: string\n /**\n * EC-378: the field the scripted UPDATE flow changes (default `title`). A user\n * turn matching {@link FakeCreateFlowChatModelOptions.updatePattern} routes to\n * the update flow instead of the create flow.\n */\n updateField?: string\n /** Routes a user turn to the update flow (default {@link FAKE_UPDATE_PATTERN}). */\n updatePattern?: RegExp\n /**\n * The answer streamed after an update proposal LANDED (default: what changed, then\n * {@link FAKE_UPDATE_FLOW_ANSWER}). A refused update always answers with the refusal.\n */\n updateAnswerText?: string\n}\n\n/** The closing sentence of a create that landed (EC-715: said only when one did). */\nexport const FAKE_CREATE_FLOW_ANSWER = 'Review the proposal below and apply it as a draft.'\n\n/** The closing sentence of an update that landed (EC-378; EC-715: said only when one did). */\nexport const FAKE_UPDATE_FLOW_ANSWER = 'Review the proposed change below and apply it as a draft.'\n\n/** What the keyless assistant says when the catalog offers nothing it may create in (EC-715). */\nexport const FAKE_NOTHING_CREATABLE_ANSWER =\n 'This project has no collection I can create a document in — singletons and the media library take no new documents.'\n\n/** Default edit-request detector of the scripted assistant (EC-378). */\nexport const FAKE_UPDATE_PATTERN = /\\b(change|update|edit|remove|replace|rewrite|fix|set)\\b/i\n\n/**\n * The scripted update flow's new value for the target field: the text after the\n * FIRST colon when present (`Set the title to: New Title` → `New Title`), else\n * the whole user text — deterministic either way. First (not last) colon so a\n * markdown body value may itself contain colons (EC-379).\n */\nexport function fakeUpdateValueFrom(userText: string): string {\n const colon = userText.indexOf(':')\n const value = colon >= 0 ? userText.slice(colon + 1) : userText\n return value.trim() || 'Updated by the assistant'\n}\n\n/**\n * The scripted update flow's TARGET FIELD (EC-379): `set/change/update the\n * <field> to: …` names it (so the playground can drive a markdown-authored\n * rich-text update deterministically, e.g. `Set the body to: ## Neu`); anything\n * else falls back to the configured default field.\n */\nexport function fakeUpdateFieldFrom(userText: string, fallback: string): string {\n return fakeUpdateTargetFrom(userText, fallback).field\n}\n\n/**\n * The scripted update flow's full TARGET (EC-593): a field, or one component prop\n * inside it — `set the <field> component <id> <prop> to: …` names a component by its\n * node id at any depth (`Set the body component p-home-quote-note value to: Hi`), so the\n * keyless playground can drive a component-prop edit through the one converter.\n */\nexport function fakeUpdateTargetFrom(\n userText: string,\n fallback: string,\n): { field: string; blockId?: string; prop?: string } {\n const match =\n /\\b(?:set|change|update)\\s+the\\s+([A-Za-z]\\w*)(?:\\s+component\\s+([\\w-]+)\\s+([A-Za-z]\\w*))?\\s+to\\s*:/i.exec(\n userText,\n )\n if (!match) return { field: fallback }\n return {\n field: match[1]!,\n ...(match[2] !== undefined && match[3] !== undefined ? { blockId: match[2], prop: match[3] } : {}),\n }\n}\n\n/** The system prompt's text (the route folds the request's context sections into it). */\nfunction systemText(prompt: FakeChatModelCallOptions['prompt']): string {\n return prompt\n .filter((message) => message.role === 'system')\n .map((message) => (typeof message.content === 'string' ? message.content : ''))\n .join('\\n\\n')\n}\n\n/** How many user turns the prompt holds — the deterministic part of a per-turn tool-call id. */\nfunction userTurnCount(prompt: FakeChatModelCallOptions['prompt']): number {\n return prompt.filter((message) => message.role === 'user').length\n}\n\n/** One tool call or tool result of the CURRENT user turn. */\nexport interface TurnToolPart {\n toolCallId: string\n toolName: string\n /** A call's parsed input. */\n input?: unknown\n /** A result's output (`{ type: 'json' | 'text' | 'error-text' | 'error-json', value }`). */\n output?: { type?: unknown; value?: unknown }\n}\n\n/** The tool calls and tool results after the last user message, in order. */\nfunction currentTurnToolParts(prompt: FakeChatModelCallOptions['prompt']): {\n calls: TurnToolPart[]\n results: TurnToolPart[]\n} {\n const calls: TurnToolPart[] = []\n const results: TurnToolPart[] = []\n for (const message of prompt.slice(lastUserIndex(prompt) + 1)) {\n if (!Array.isArray(message.content)) continue\n for (const part of message.content) {\n const candidate = part as {\n type?: unknown\n toolCallId?: unknown\n toolName?: unknown\n input?: unknown\n output?: unknown\n }\n if (typeof candidate.toolCallId !== 'string' || typeof candidate.toolName !== 'string') continue\n if (candidate.type === 'tool-call') {\n let input = candidate.input\n if (typeof input === 'string') {\n try {\n input = JSON.parse(input) as unknown\n } catch {\n input = undefined\n }\n }\n calls.push({ toolCallId: candidate.toolCallId, toolName: candidate.toolName, input })\n } else if (candidate.type === 'tool-result') {\n results.push({\n toolCallId: candidate.toolCallId,\n toolName: candidate.toolName,\n output: (candidate.output ?? {}) as TurnToolPart['output'],\n })\n }\n }\n }\n return { calls, results }\n}\n\n/** A tool result's error text, or `undefined` when the tool succeeded. */\nfunction toolError(result: TurnToolPart): string | undefined {\n const output = result.output ?? {}\n if (output.type === 'error-text') return typeof output.value === 'string' ? output.value : 'the tool failed'\n if (output.type === 'error-json') return JSON.stringify(output.value)\n if (output.type === 'execution-denied') return 'the tool call was denied'\n return undefined\n}\n\n/** A successful tool result's JSON value (`{}` for anything else). */\nfunction toolJson(result: TurnToolPart): Record<string, unknown> {\n const value = result.output?.type === 'json' ? result.output.value : undefined\n return typeof value === 'object' && value !== null && !Array.isArray(value) ? (value as Record<string, unknown>) : {}\n}\n\nfunction escapeRegExp(text: string): string {\n return text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\n/** Where the user's text first names a collection (its id or label, plural allowed), or -1. */\nfunction namedAt(entry: CatalogCollection, text: string): number {\n const terms = [entry.id, ...(entry.label !== undefined ? [entry.label] : [])]\n let best = -1\n for (const term of terms) {\n const match = new RegExp(`\\\\b${escapeRegExp(term)}s?\\\\b`, 'i').exec(text)\n if (match && (best < 0 || match.index < best)) best = match.index\n }\n return best\n}\n\n/**\n * The collection a keyless create targets (EC-715), read off the catalog the system prompt\n * carries — never a hardcoded name: one the user's text NAMES (id or label; the earliest\n * mention wins), else the collection of the document open in the editor, else the first\n * creatable one. A singleton or the media library is never a create target.\n */\nexport function chooseCreateCollection(\n catalog: readonly CatalogCollection[],\n userText: string,\n openCollection: string | undefined,\n): CatalogCollection | undefined {\n const creatable = catalog.filter((entry) => !entry.singleton && !entry.assetLibrary)\n let named: CatalogCollection | undefined\n let namedIndex = -1\n for (const entry of creatable) {\n const index = namedAt(entry, userText)\n if (index >= 0 && (namedIndex < 0 || index < namedIndex)) {\n named = entry\n namedIndex = index\n }\n }\n return named ?? creatable.find((entry) => entry.id === openCollection) ?? creatable[0]\n}\n\n/** A collection's name in an answer: its label, else its id. */\nfunction collectionName(catalog: readonly CatalogCollection[], id: unknown): string {\n const entry = catalog.find((candidate) => candidate.id === id)\n return entry?.label ?? (typeof id === 'string' ? id : 'document')\n}\n\n/**\n * The create flow's answer, DERIVED from the `createDocument` result (EC-715): a refused\n * create states the refusal, quoting the error; a proposal says what was drafted and which\n * positions it left empty (`unfilled`). It used to say \"Done\" whatever the result said.\n */\nexport function fakeCreateAnswer(\n result: TurnToolPart,\n catalog: readonly CatalogCollection[],\n collection: unknown,\n successText?: string,\n): string {\n const name = collectionName(catalog, collection)\n const error = toolError(result)\n if (error !== undefined) return `I could not draft the ${name}: ${error}`\n const output = toolJson(result)\n if (output.status !== 'proposed') return `The ${name} was not drafted.`\n if (successText !== undefined) return successText\n const title = typeof output.title === 'string' ? ` \"${output.title}\"` : ''\n const unfilled = Array.isArray(output.unfilled)\n ? output.unfilled.filter((entry): entry is string => typeof entry === 'string')\n : []\n const skipped = unfilled.length > 0 ? ` Left empty: ${unfilled.join('; ')}.` : ''\n return `I drafted a new ${name}${title}.${skipped} ${FAKE_CREATE_FLOW_ANSWER}`\n}\n\n/**\n * The update flow's answer, DERIVED from the tool results (EC-715): a refused update states\n * the refusal, quoting the error; a proposal names what changed.\n */\nexport function fakeUpdateAnswer(result: TurnToolPart, successText?: string): string {\n const error = toolError(result)\n if (error !== undefined) return `I could not change it: ${error}`\n const output = toolJson(result)\n if (output.status === 'no-change') {\n return typeof output.note === 'string' ? output.note : 'There is nothing to change.'\n }\n if (output.status !== 'proposed') return 'Nothing was changed.'\n if (successText !== undefined) return successText\n const changed = Array.isArray(output.changedFields)\n ? output.changedFields.filter((entry): entry is string => typeof entry === 'string')\n : []\n return `I proposed a change to ${changed.length > 0 ? changed.join(', ') : 'the document'}. ${FAKE_UPDATE_FLOW_ANSWER}`\n}\n\n/**\n * A scripted, STATELESS fake chat model that drives the FULL create flow — and,\n * for a user turn matching the update pattern, the EC-378 UPDATE flow — over the\n * native loop (EC-334): keyless playground / CI exercise the whole client-tool\n * round-trip deterministically. Stage is read from the CURRENT user turn's tool\n * calls and results (prompt suffix after the last user message), so every follow-up\n * turn starts a fresh flow — multi-turn works without model state.\n *\n * EC-715: it reads THE PROJECT, never a hardcoded collection — the catalog and the open\n * document arrive in the system prompt (the route has no data access; that prose is the only\n * channel), read back by `parseCollectionCatalog` / `parseCurrentDocumentSection`. Every\n * answer is derived from the tool results (a refusal is said, never \"Done\"), and every tool\n * call id carries the user-turn number, so a second proposal never replaces the first card.\n *\n * Create flow:\n * 1. the target: {@link chooseCreateCollection} (none creatable → it says so);\n * 2. each REQUIRED relation target not yet searched this turn → `searchDocuments`;\n * 3. the target has an asset field (or `searchAssets`) and the library was not listed\n * this turn → `listAssets({ query?: assetQuery })`;\n * 4. → `createDocument({ collection, instruction: <last user text> })`;\n * 5. a `createDocument` result → {@link fakeCreateAnswer}.\n *\n * Update flow (user text matches `updatePattern`, e.g. \"Change the title to: X\"):\n * 1. no tool result yet → `getDocument({})` — target omitted on purpose:\n * the executor resolves the document OPEN in the\n * editor (the EC-378 current-document seam)\n * 2. document read → `updateFields({ changes: [{\n * ...fakeUpdateTargetFrom(<text>, updateField),\n * value: fakeUpdateValueFrom(<last user text>) }] })`\n * — \"Set the body to: ## Neu\" drives a markdown\n * rich-text update deterministically (EC-379);\n * \"Set the body component <id> <prop> to: X\" one\n * component prop at any depth (EC-593); a refused read\n * answers with the refusal instead\n * 3. update result present → {@link fakeUpdateAnswer}.\n */\nexport function createFakeCreateFlowChatModel(\n options: FakeCreateFlowChatModelOptions = {},\n): FakeChatModel {\n const updateField = options.updateField ?? 'title'\n const updatePattern = options.updatePattern ?? FAKE_UPDATE_PATTERN\n return createFakeChatModel({\n modelId: options.modelId ?? 'fake-create-flow-model',\n script: (callOptions) => {\n const prompt = callOptions.prompt\n const turn = userTurnCount(prompt)\n const { calls, results } = currentTurnToolParts(prompt)\n const resultOf = (toolName: string) => results.find((result) => result.toolName === toolName)\n const userText = lastUserText(prompt)\n\n if (updatePattern.test(userText)) {\n const updated = resultOf('updateFields')\n if (updated) return answerTurnParts(fakeUpdateAnswer(updated, options.updateAnswerText))\n const read = resultOf('getDocument')\n if (read) {\n const error = toolError(read)\n if (error !== undefined) return answerTurnParts(`I could not read the document: ${error}`)\n return toolTurnParts(\n 'Proposing the change. ',\n 'updateFields',\n { changes: [{ ...fakeUpdateTargetFrom(userText, updateField), value: fakeUpdateValueFrom(userText) }] },\n `call-update-${turn}`,\n )\n }\n return toolTurnParts('Reading the document. ', 'getDocument', {}, `call-get-${turn}`)\n }\n\n const system = systemText(prompt)\n const catalog = parseCollectionCatalog(system)\n const created = resultOf('createDocument')\n if (created) {\n const call = calls.find((candidate) => candidate.toolCallId === created.toolCallId)\n const collection = (call?.input as { collection?: unknown } | undefined)?.collection\n return answerTurnParts(fakeCreateAnswer(created, catalog, collection, options.answerText))\n }\n const target = chooseCreateCollection(catalog, userText, parseCurrentDocumentSection(system)?.collection)\n if (!target) return answerTurnParts(FAKE_NOTHING_CREATABLE_ANSWER)\n\n // EC-715: every REQUIRED relation target, once per turn (the blog kit's post needs its\n // author) — searched in catalog order.\n const answered = new Set(results.map((result) => result.toolCallId))\n const searched = new Set(\n calls\n .filter((call) => call.toolName === 'searchDocuments' && answered.has(call.toolCallId))\n .map((call) => (call.input as { collection?: unknown } | undefined)?.collection),\n )\n const targets = [...new Set(target.relations.filter((relation) => relation.required).map((relation) => relation.target))]\n const next = targets.findIndex((relationTarget) => !searched.has(relationTarget))\n if (next >= 0) {\n return toolTurnParts(\n FAKE_CHAT_PREAMBLE,\n 'searchDocuments',\n { collection: targets[next] },\n `call-search-${turn}-${next + 1}`,\n )\n }\n // EC-381 — search the media library before creating (a topically fitting, REAL asset\n // fills the image field via the enum leash).\n const searchAssets = options.searchAssets ?? target.assetFields.length > 0\n if (searchAssets && !resultOf('listAssets')) {\n return toolTurnParts(\n 'Looking for a fitting image. ',\n 'listAssets',\n { ...(options.assetQuery ? { query: options.assetQuery } : {}) },\n `call-assets-${turn}`,\n )\n }\n return toolTurnParts(\n 'Drafting a proposal. ',\n 'createDocument',\n { collection: target.id, instruction: userText || 'Write a short document.' },\n `call-create-${turn}`,\n )\n },\n })\n}\n\n// --- Fake provider ------------------------------------------------------------------\n\nexport interface FakeProviderOptions {\n /** Provider id (default `fake`). */\n id?: string\n /** Model id recorded in provenance (default `fake-model`). */\n model?: string\n /** Reported capabilities (default: both true). Set to test the capability gate. */\n capabilities?: AiProviderCapabilities\n /** Scripted objects returned in call order; the last entry is reused when exhausted. */\n objects?: unknown[]\n /** Compute the object from the request + zero-based call index (overrides `objects`). */\n respond?: (request: GenerateStructuredRequest, callIndex: number) => unknown\n /** The scripted chat model `languageModel()` serves (default {@link createFakeChatModel}). */\n chatModel?: FakeChatModel\n}\n\n/** A FakeProvider that also records the requests it received, for assertions. */\nexport interface FakeProvider extends AiProvider {\n /** Every `generateStructured` request received, in order. */\n readonly calls: GenerateStructuredRequest[]\n /** The scripted fake chat model behind `languageModel()` (records its calls). */\n readonly chatModel: FakeChatModel\n}\n\nexport function createFakeProvider(options: FakeProviderOptions = {}): FakeProvider {\n const calls: GenerateStructuredRequest[] = []\n const objects = options.objects ?? []\n const chatModel = options.chatModel ?? createFakeChatModel()\n let index = 0\n\n return {\n id: options.id ?? 'fake',\n model: options.model ?? 'fake-model',\n calls,\n chatModel,\n capabilities: (): AiProviderCapabilities =>\n options.capabilities ?? { toolCalling: true, structuredOutput: true },\n\n languageModel: () => Promise.resolve(chatModel),\n\n generateStructured(request) {\n calls.push(request)\n const callIndex = index\n index += 1\n const object = options.respond\n ? options.respond(request, callIndex)\n : objects.length > 0\n ? objects[Math.min(callIndex, objects.length - 1)]\n : {}\n return Promise.resolve({ object, usage: { inputTokens: 0, outputTokens: 0 } })\n },\n }\n}\n"]}
|
package/dist/lib/ai/index.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ export * from './update-fields.js';
|
|
|
34
34
|
export * from './anthropic-provider.js';
|
|
35
35
|
export * from './gateway-provider.js';
|
|
36
36
|
export * from './fake-provider.js';
|
|
37
|
+
export * from './keyless-assistant.js';
|
|
37
38
|
export * from './route.js';
|
|
38
39
|
export * from './route-fetch.js';
|
|
39
40
|
export * from './route-provider.js';
|
package/dist/lib/ai/index.js
CHANGED
|
@@ -34,6 +34,7 @@ export * from './update-fields.js';
|
|
|
34
34
|
export * from './anthropic-provider.js';
|
|
35
35
|
export * from './gateway-provider.js';
|
|
36
36
|
export * from './fake-provider.js';
|
|
37
|
+
export * from './keyless-assistant.js';
|
|
37
38
|
export * from './route.js';
|
|
38
39
|
export * from './route-fetch.js';
|
|
39
40
|
export * from './route-provider.js';
|
package/dist/lib/ai/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/ai/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,SAAS,CAAA;AAEhC,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA;AAC7B,cAAc,SAAS,CAAA;AACvB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,0BAA0B,CAAA;AACxC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,SAAS,CAAA;AACvB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA","sourcesContent":["/**\n * `@elytracms/studio/lib/ai` — the headless AI platform seam (EC-331, phase 1).\n *\n * Public surface: the config gate, the provider adapters (Anthropic + Fake), the\n * knowledge mechanism, the target-shape derivation, the `applyContentWithShape`\n * engine, the server-route factory, and the provenance seam. No chat UI here.\n *\n * Bundle discipline: nothing exported here statically imports `ai` / `@ai-sdk/*` —\n * only `anthropic-provider` touches them, via dynamic `import()`. So importing this\n * barrel never eagerly loads the AI SDK, and a studio without an `ai` config block\n * (which only references `StudioAiConfig` as a type) reaches none of it. The same\n * discipline keeps `jose` (the session resolver's JWT library) behind a dynamic\n * `import()` in `convex-session`.\n *\n * EC-371 adds the engine-default session gate + mounting kit: the Convex JWT\n * session resolver (server), the matching client header provider, and the Node\n * `(req, res)` bridge. The Vite DEV mount lives in its own entry —\n * `@elytracms/studio/lib/ai/vite` (`createAiDevPlugin`) — because it imports `vite`,\n * a dev-only tool that must stay out of this barrel's dependency edge.\n */\nexport const PACKAGE = './index'\n\nexport * from './types'\nexport * from './config'\nexport * from './provenance'\nexport * from './knowledge'\nexport * from './rich-text-input'\nexport * from './constraints'\nexport * from './proposal-validation'\nexport * from './leash'\nexport * from './writer-form'\nexport * from './shape'\nexport * from './apply-content'\nexport * from './update-fields'\nexport * from './anthropic-provider'\nexport * from './gateway-provider'\nexport * from './fake-provider'\nexport * from './route'\nexport * from './route-fetch'\nexport * from './route-provider'\nexport * from './convex-session'\nexport * from './convex-session-headers'\nexport * from './node-handler'\nexport * from './tools'\nexport * from './chat-context'\nexport * from './chat-loop'\nexport * from './chat-state'\nexport * from './rich-text-translate'\nexport * from './translate-document'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/ai/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,SAAS,CAAA;AAEhC,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA;AAC7B,cAAc,SAAS,CAAA;AACvB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,qBAAqB,CAAA;AACnC,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,0BAA0B,CAAA;AACxC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,SAAS,CAAA;AACvB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA","sourcesContent":["/**\n * `@elytracms/studio/lib/ai` — the headless AI platform seam (EC-331, phase 1).\n *\n * Public surface: the config gate, the provider adapters (Anthropic + Fake), the\n * knowledge mechanism, the target-shape derivation, the `applyContentWithShape`\n * engine, the server-route factory, and the provenance seam. No chat UI here.\n *\n * Bundle discipline: nothing exported here statically imports `ai` / `@ai-sdk/*` —\n * only `anthropic-provider` touches them, via dynamic `import()`. So importing this\n * barrel never eagerly loads the AI SDK, and a studio without an `ai` config block\n * (which only references `StudioAiConfig` as a type) reaches none of it. The same\n * discipline keeps `jose` (the session resolver's JWT library) behind a dynamic\n * `import()` in `convex-session`.\n *\n * EC-371 adds the engine-default session gate + mounting kit: the Convex JWT\n * session resolver (server), the matching client header provider, and the Node\n * `(req, res)` bridge. The Vite DEV mount lives in its own entry —\n * `@elytracms/studio/lib/ai/vite` (`createAiDevPlugin`) — because it imports `vite`,\n * a dev-only tool that must stay out of this barrel's dependency edge.\n */\nexport const PACKAGE = './index'\n\nexport * from './types'\nexport * from './config'\nexport * from './provenance'\nexport * from './knowledge'\nexport * from './rich-text-input'\nexport * from './constraints'\nexport * from './proposal-validation'\nexport * from './leash'\nexport * from './writer-form'\nexport * from './shape'\nexport * from './apply-content'\nexport * from './update-fields'\nexport * from './anthropic-provider'\nexport * from './gateway-provider'\nexport * from './fake-provider'\nexport * from './keyless-assistant'\nexport * from './route'\nexport * from './route-fetch'\nexport * from './route-provider'\nexport * from './convex-session'\nexport * from './convex-session-headers'\nexport * from './node-handler'\nexport * from './tools'\nexport * from './chat-context'\nexport * from './chat-loop'\nexport * from './chat-state'\nexport * from './rich-text-translate'\nexport * from './translate-document'\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { FakeProvider } from './fake-provider.js';
|
|
2
|
+
import type { GenerateStructuredRequest } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* What a keyless draft writes about: the instruction's `about …` clause, else the
|
|
5
|
+
* instruction without its leading imperative — read off the authoring prompt
|
|
6
|
+
* (`Instruction:\n…`, `applyContentWithShape`'s first part).
|
|
7
|
+
*/
|
|
8
|
+
export declare function keylessTopic(prompt: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* The keyless DRAFT (EC-715): a deterministic document for a create's target shape. It fills
|
|
11
|
+
* every position the shape offers — text from the instruction's topic, the first offered id
|
|
12
|
+
* of a relation or asset enum, nested objects recursively — and leaves a date, an unbounded
|
|
13
|
+
* list and anything unrecognised empty (the engine lists those on the proposal).
|
|
14
|
+
*/
|
|
15
|
+
export declare function keylessDraft(request: GenerateStructuredRequest): Record<string, unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* The keyless TRANSLATION: every human-readable segment prefixed with the target locale
|
|
18
|
+
* (`[de] …`), placeholder tokens kept verbatim — visible, so a live check can see which locale
|
|
19
|
+
* each fill came from.
|
|
20
|
+
*/
|
|
21
|
+
export declare function keylessTranslate(request: GenerateStructuredRequest): unknown;
|
|
22
|
+
/** The keyless structured responder: a translation batch, else a create's draft. */
|
|
23
|
+
export declare function keylessRespond(request: GenerateStructuredRequest): unknown;
|
|
24
|
+
export interface KeylessProviderOptions {
|
|
25
|
+
/** Provider id recorded in provenance (default `fake`). */
|
|
26
|
+
id?: string;
|
|
27
|
+
/** Model id recorded in provenance (default `fake-model`). */
|
|
28
|
+
model?: string;
|
|
29
|
+
/** Whether a create lists the media library first (default: when the collection has an asset field). */
|
|
30
|
+
searchAssets?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* THE keyless provider (EC-715): the project-reading scripted conversation plus the draft and
|
|
34
|
+
* translation responders, as one `AiProvider`. A host's AI handler falls back to it when no
|
|
35
|
+
* key is set.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createKeylessProvider(options?: KeylessProviderOptions): FakeProvider;
|