@fluidframework/ai-collab 2.22.1 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/README.md +70 -4
- package/api-report/ai-collab.alpha.api.md +170 -2
- package/dist/aiCollab.d.ts +0 -1
- package/dist/aiCollab.d.ts.map +1 -1
- package/dist/aiCollab.js +1 -2
- package/dist/aiCollab.js.map +1 -1
- package/dist/aiCollabApi.d.ts +50 -3
- package/dist/aiCollabApi.d.ts.map +1 -1
- package/dist/aiCollabApi.js.map +1 -1
- package/dist/alpha.d.ts +17 -0
- package/dist/explicit-strategy/debugEvents.d.ts +248 -0
- package/dist/explicit-strategy/debugEvents.d.ts.map +1 -0
- package/dist/explicit-strategy/debugEvents.js +36 -0
- package/dist/explicit-strategy/debugEvents.js.map +1 -0
- package/dist/explicit-strategy/index.d.ts +4 -4
- package/dist/explicit-strategy/index.d.ts.map +1 -1
- package/dist/explicit-strategy/index.js +176 -54
- package/dist/explicit-strategy/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/lib/aiCollab.d.ts +0 -1
- package/lib/aiCollab.d.ts.map +1 -1
- package/lib/aiCollab.js +1 -2
- package/lib/aiCollab.js.map +1 -1
- package/lib/aiCollabApi.d.ts +50 -3
- package/lib/aiCollabApi.d.ts.map +1 -1
- package/lib/aiCollabApi.js.map +1 -1
- package/lib/alpha.d.ts +17 -0
- package/lib/explicit-strategy/debugEvents.d.ts +248 -0
- package/lib/explicit-strategy/debugEvents.d.ts.map +1 -0
- package/lib/explicit-strategy/debugEvents.js +32 -0
- package/lib/explicit-strategy/debugEvents.js.map +1 -0
- package/lib/explicit-strategy/index.d.ts +4 -4
- package/lib/explicit-strategy/index.d.ts.map +1 -1
- package/lib/explicit-strategy/index.js +174 -52
- package/lib/explicit-strategy/index.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/package.json +13 -11
- package/src/aiCollab.ts +1 -2
- package/src/aiCollabApi.ts +54 -3
- package/src/explicit-strategy/debugEvents.ts +297 -0
- package/src/explicit-strategy/index.ts +269 -59
- package/src/index.ts +20 -0
|
@@ -5,16 +5,18 @@
|
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.generateTreeEdits = void 0;
|
|
8
|
-
const internal_1 = require("@fluidframework/
|
|
8
|
+
const internal_1 = require("@fluidframework/telemetry-utils/internal");
|
|
9
|
+
const internal_2 = require("@fluidframework/tree/internal");
|
|
9
10
|
// eslint-disable-next-line import/no-internal-modules
|
|
10
11
|
const zod_1 = require("openai/helpers/zod");
|
|
12
|
+
const uuid_1 = require("uuid");
|
|
11
13
|
const zod_2 = require("zod");
|
|
12
14
|
const agentEditReducer_js_1 = require("./agentEditReducer.js");
|
|
15
|
+
const debugEvents_js_1 = require("./debugEvents.js");
|
|
13
16
|
const idGenerator_js_1 = require("./idGenerator.js");
|
|
14
17
|
const promptGeneration_js_1 = require("./promptGeneration.js");
|
|
15
18
|
const typeGeneration_js_1 = require("./typeGeneration.js");
|
|
16
19
|
const utils_js_1 = require("./utils.js");
|
|
17
|
-
const DEBUG_LOG = [];
|
|
18
20
|
/**
|
|
19
21
|
* Prompts the provided LLM client to generate valid tree edits.
|
|
20
22
|
* Applies those edits to the provided tree branch before returning.
|
|
@@ -30,59 +32,94 @@ async function generateTreeEdits(options) {
|
|
|
30
32
|
const editLog = [];
|
|
31
33
|
let editCount = 0;
|
|
32
34
|
let sequentialErrorCount = 0;
|
|
33
|
-
const simpleSchema = (0,
|
|
35
|
+
const simpleSchema = (0, internal_2.getSimpleSchema)(internal_2.Tree.schema(options.treeNode));
|
|
34
36
|
const tokensUsed = { inputTokens: 0, outputTokens: 0 };
|
|
37
|
+
const debugLogTraceId = (0, uuid_1.v4)();
|
|
38
|
+
const coreEventFlowTraceId = (0, uuid_1.v4)();
|
|
39
|
+
options.debugEventLogHandler?.({
|
|
40
|
+
...(0, debugEvents_js_1.generateDebugEvent)("CORE_EVENT_LOOP_STARTED", debugLogTraceId),
|
|
41
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.CORE_EVENT_LOOP,
|
|
42
|
+
eventFlowStatus: "STARTED",
|
|
43
|
+
eventFlowTraceId: coreEventFlowTraceId,
|
|
44
|
+
});
|
|
35
45
|
try {
|
|
36
|
-
for await (const
|
|
46
|
+
for await (const generateEditResult of generateEdits(options, simpleSchema, idGenerator, editLog, options.limiters?.tokenLimits, tokensUsed, options.debugEventLogHandler && {
|
|
47
|
+
eventLogHandler: options.debugEventLogHandler,
|
|
48
|
+
traceId: debugLogTraceId,
|
|
49
|
+
})) {
|
|
37
50
|
try {
|
|
38
|
-
const result = (0, agentEditReducer_js_1.applyAgentEdit)(edit, idGenerator, simpleSchema.definitions, options.validator);
|
|
51
|
+
const result = (0, agentEditReducer_js_1.applyAgentEdit)(generateEditResult.edit, idGenerator, simpleSchema.definitions, options.validator);
|
|
39
52
|
const explanation = result.explanation;
|
|
40
53
|
editLog.push({ edit: { ...result, explanation } });
|
|
41
54
|
sequentialErrorCount = 0;
|
|
55
|
+
options.debugEventLogHandler?.({
|
|
56
|
+
...(0, debugEvents_js_1.generateDebugEvent)("APPLIED_EDIT_SUCCESS", debugLogTraceId),
|
|
57
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,
|
|
58
|
+
eventFlowStatus: "IN_PROGRESS",
|
|
59
|
+
eventFlowTraceId: generateEditResult.eventFlowTraceId,
|
|
60
|
+
edit: generateEditResult.edit,
|
|
61
|
+
});
|
|
42
62
|
}
|
|
43
63
|
catch (error) {
|
|
44
|
-
|
|
64
|
+
options.debugEventLogHandler?.({
|
|
65
|
+
...(0, debugEvents_js_1.generateDebugEvent)("APPLIED_EDIT_FAILURE", debugLogTraceId),
|
|
66
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,
|
|
67
|
+
eventFlowStatus: "IN_PROGRESS",
|
|
68
|
+
eventFlowTraceId: generateEditResult.eventFlowTraceId,
|
|
69
|
+
edit: generateEditResult.edit,
|
|
70
|
+
errorMessage: error?.message,
|
|
71
|
+
sequentialErrorCount,
|
|
72
|
+
});
|
|
73
|
+
if (error instanceof internal_1.UsageError) {
|
|
45
74
|
sequentialErrorCount += 1;
|
|
46
|
-
editLog.push({ edit, error: error.message });
|
|
47
|
-
DEBUG_LOG?.push(`Error: ${error.message}`);
|
|
75
|
+
editLog.push({ edit: generateEditResult.edit, error: error.message });
|
|
48
76
|
}
|
|
49
77
|
else {
|
|
50
78
|
throw error;
|
|
51
79
|
}
|
|
52
80
|
}
|
|
53
|
-
|
|
81
|
+
let shouldExitEarly = false;
|
|
82
|
+
const completionResponse = {
|
|
83
|
+
status: editCount > 0 && sequentialErrorCount < editCount ? "partial-failure" : "failure",
|
|
84
|
+
errorMessage: "unexpectedError",
|
|
85
|
+
tokensUsed,
|
|
86
|
+
};
|
|
54
87
|
if (options.limiters?.abortController?.signal.aborted === true) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
errorMessage: "aborted",
|
|
58
|
-
tokensUsed,
|
|
59
|
-
};
|
|
88
|
+
completionResponse.errorMessage = "aborted";
|
|
89
|
+
shouldExitEarly = true;
|
|
60
90
|
}
|
|
61
|
-
if (sequentialErrorCount >
|
|
91
|
+
else if (sequentialErrorCount >
|
|
62
92
|
(options.limiters?.maxSequentialErrors ?? Number.POSITIVE_INFINITY)) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
93
|
+
completionResponse.errorMessage = "tooManyErrors";
|
|
94
|
+
shouldExitEarly = true;
|
|
95
|
+
}
|
|
96
|
+
else if (++editCount >= (options.limiters?.maxModelCalls ?? Number.POSITIVE_INFINITY)) {
|
|
97
|
+
completionResponse.errorMessage = "tooManyModelCalls";
|
|
98
|
+
shouldExitEarly = true;
|
|
68
99
|
}
|
|
69
|
-
if (
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
100
|
+
if (shouldExitEarly) {
|
|
101
|
+
options.debugEventLogHandler?.({
|
|
102
|
+
...(0, debugEvents_js_1.generateDebugEvent)("CORE_EVENT_LOOP_COMPLETED", debugLogTraceId),
|
|
103
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.CORE_EVENT_LOOP,
|
|
104
|
+
eventFlowStatus: "COMPLETED",
|
|
105
|
+
status: "failure",
|
|
106
|
+
failureReason: completionResponse.errorMessage,
|
|
107
|
+
eventFlowTraceId: coreEventFlowTraceId,
|
|
108
|
+
});
|
|
109
|
+
return completionResponse;
|
|
75
110
|
}
|
|
76
111
|
}
|
|
77
112
|
}
|
|
78
113
|
catch (error) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
114
|
+
options.debugEventLogHandler?.({
|
|
115
|
+
...(0, debugEvents_js_1.generateDebugEvent)("CORE_EVENT_LOOP_COMPLETED", debugLogTraceId),
|
|
116
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.CORE_EVENT_LOOP,
|
|
117
|
+
eventFlowStatus: "COMPLETED",
|
|
118
|
+
status: "failure",
|
|
119
|
+
eventFlowTraceId: coreEventFlowTraceId,
|
|
120
|
+
failureReason: error instanceof TokenLimitExceededError ? "tokenLimitExceeded" : "unexpectedError",
|
|
121
|
+
errorMessage: error?.message,
|
|
122
|
+
});
|
|
86
123
|
if (error instanceof TokenLimitExceededError) {
|
|
87
124
|
return {
|
|
88
125
|
status: editCount > 0 && sequentialErrorCount < editCount ? "partial-failure" : "failure",
|
|
@@ -92,10 +129,13 @@ async function generateTreeEdits(options) {
|
|
|
92
129
|
}
|
|
93
130
|
throw error;
|
|
94
131
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
132
|
+
options.debugEventLogHandler?.({
|
|
133
|
+
...(0, debugEvents_js_1.generateDebugEvent)("CORE_EVENT_LOOP_COMPLETED", debugLogTraceId),
|
|
134
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.CORE_EVENT_LOOP,
|
|
135
|
+
eventFlowStatus: "COMPLETED",
|
|
136
|
+
eventFlowTraceId: coreEventFlowTraceId,
|
|
137
|
+
status: "success",
|
|
138
|
+
});
|
|
99
139
|
return {
|
|
100
140
|
status: "success",
|
|
101
141
|
tokensUsed,
|
|
@@ -111,14 +151,31 @@ exports.generateTreeEdits = generateTreeEdits;
|
|
|
111
151
|
* Once the LLM believes it has completed the user's ask, it will no longer return an edit and as a result
|
|
112
152
|
* this generator will no longer yield a next value.
|
|
113
153
|
*/
|
|
114
|
-
async function* generateEdits(options, simpleSchema, idGenerator, editLog, tokenLimits, tokensUsed) {
|
|
154
|
+
async function* generateEdits(options, simpleSchema, idGenerator, editLog, tokenLimits, tokensUsed, debugOptions) {
|
|
115
155
|
const [types, rootTypeName] = (0, typeGeneration_js_1.generateGenericEditTypes)(simpleSchema, true);
|
|
116
156
|
let plan;
|
|
117
157
|
if (options.planningStep !== undefined) {
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
158
|
+
const planningPrompt = (0, promptGeneration_js_1.getPlanningSystemPrompt)(options.treeNode, options.prompt.userAsk, options.prompt.systemRoleContext);
|
|
159
|
+
const generatePlanningPromptEventFlowId = (0, uuid_1.v4)();
|
|
160
|
+
debugOptions?.eventLogHandler?.({
|
|
161
|
+
...(0, debugEvents_js_1.generateDebugEvent)("GENERATE_PLANNING_PROMPT_STARTED", debugOptions.traceId),
|
|
162
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.GENERATE_PLANNING_PROMPT,
|
|
163
|
+
eventFlowTraceId: generatePlanningPromptEventFlowId,
|
|
164
|
+
eventFlowStatus: "STARTED",
|
|
165
|
+
});
|
|
166
|
+
plan = await getStringFromLlm(planningPrompt, options.openAI, tokensUsed, debugOptions && {
|
|
167
|
+
...debugOptions,
|
|
168
|
+
triggeringEventFlowName: debugEvents_js_1.EventFlowDebugNames.GENERATE_PLANNING_PROMPT,
|
|
169
|
+
eventFlowTraceId: generatePlanningPromptEventFlowId,
|
|
170
|
+
});
|
|
171
|
+
debugOptions?.eventLogHandler?.({
|
|
172
|
+
...(0, debugEvents_js_1.generateDebugEvent)("GENERATE_PLANNING_PROMPT_COMPLETED", debugOptions.traceId),
|
|
173
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.GENERATE_PLANNING_PROMPT,
|
|
174
|
+
eventFlowStatus: "COMPLETED",
|
|
175
|
+
eventFlowTraceId: generatePlanningPromptEventFlowId,
|
|
176
|
+
isLlmResponseValid: plan !== undefined,
|
|
177
|
+
llmGeneratedPlan: plan,
|
|
178
|
+
});
|
|
122
179
|
}
|
|
123
180
|
const originalDecoratedJson = (options.finalReviewStep ?? false)
|
|
124
181
|
? (0, promptGeneration_js_1.toDecoratedJson)(idGenerator, options.treeNode)
|
|
@@ -127,21 +184,35 @@ async function* generateEdits(options, simpleSchema, idGenerator, editLog, token
|
|
|
127
184
|
let hasReviewed = (options.finalReviewStep ?? false) ? false : true;
|
|
128
185
|
async function getNextEdit() {
|
|
129
186
|
const systemPrompt = (0, promptGeneration_js_1.getEditingSystemPrompt)(options.prompt.userAsk, idGenerator, options.treeNode, editLog, options.prompt.systemRoleContext, plan);
|
|
130
|
-
DEBUG_LOG?.push(systemPrompt);
|
|
131
187
|
const schema = types[rootTypeName] ?? (0, utils_js_1.fail)("Root type not found.");
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
188
|
+
const generateTreeEditEventFlowId = (0, uuid_1.v4)();
|
|
189
|
+
debugOptions?.eventLogHandler?.({
|
|
190
|
+
...(0, debugEvents_js_1.generateDebugEvent)("GENERATE_TREE_EDIT_STARTED", debugOptions.traceId),
|
|
191
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,
|
|
192
|
+
eventFlowStatus: "STARTED",
|
|
193
|
+
eventFlowTraceId: generateTreeEditEventFlowId,
|
|
194
|
+
llmPrompt: systemPrompt,
|
|
195
|
+
});
|
|
196
|
+
const wrapper = await getStructuredOutputFromLlm(systemPrompt, options.openAI, schema, "A JSON object that represents an edit to a JSON tree.", tokensUsed, debugOptions && {
|
|
197
|
+
...debugOptions,
|
|
198
|
+
triggeringEventFlowName: debugEvents_js_1.EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,
|
|
199
|
+
eventFlowTraceId: generateTreeEditEventFlowId,
|
|
200
|
+
});
|
|
201
|
+
debugOptions?.eventLogHandler?.({
|
|
202
|
+
...(0, debugEvents_js_1.generateDebugEvent)("GENERATE_TREE_EDIT_COMPLETED", debugOptions.traceId),
|
|
203
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,
|
|
204
|
+
eventFlowStatus: "COMPLETED",
|
|
205
|
+
eventFlowTraceId: generateTreeEditEventFlowId,
|
|
206
|
+
isLlmResponseValid: wrapper?.edit !== undefined,
|
|
207
|
+
llmGeneratedEdit: wrapper?.edit,
|
|
208
|
+
});
|
|
135
209
|
if (wrapper === undefined) {
|
|
136
|
-
DEBUG_LOG?.push("Failed to get response");
|
|
137
210
|
return undefined;
|
|
138
211
|
}
|
|
139
212
|
if (wrapper.edit === null) {
|
|
140
|
-
DEBUG_LOG?.push("No more edits.");
|
|
141
213
|
if ((options.finalReviewStep ?? false) && !hasReviewed) {
|
|
142
214
|
const reviewResult = await reviewGoal();
|
|
143
215
|
if (reviewResult === undefined) {
|
|
144
|
-
DEBUG_LOG?.push("Failed to get review response");
|
|
145
216
|
return undefined;
|
|
146
217
|
}
|
|
147
218
|
// eslint-disable-next-line require-atomic-updates
|
|
@@ -157,18 +228,40 @@ async function* generateEdits(options, simpleSchema, idGenerator, editLog, token
|
|
|
157
228
|
}
|
|
158
229
|
}
|
|
159
230
|
else {
|
|
160
|
-
return wrapper.edit;
|
|
231
|
+
return { edit: wrapper.edit, eventFlowTraceId: generateTreeEditEventFlowId };
|
|
161
232
|
}
|
|
162
233
|
}
|
|
163
234
|
async function reviewGoal() {
|
|
164
235
|
const systemPrompt = (0, promptGeneration_js_1.getReviewSystemPrompt)(options.prompt.userAsk, idGenerator, options.treeNode, originalDecoratedJson ?? (0, utils_js_1.fail)("Original decorated tree not provided."), options.prompt.systemRoleContext);
|
|
165
|
-
DEBUG_LOG?.push(systemPrompt);
|
|
166
236
|
const schema = zod_2.z.object({
|
|
167
237
|
goalAccomplished: zod_2.z
|
|
168
238
|
.enum(["yes", "no"])
|
|
169
239
|
.describe('Whether the user\'s goal was met in the "after" tree.'),
|
|
170
240
|
});
|
|
171
|
-
|
|
241
|
+
const finalReviewEventFlowTraceId = (0, uuid_1.v4)();
|
|
242
|
+
debugOptions?.eventLogHandler?.({
|
|
243
|
+
...(0, debugEvents_js_1.generateDebugEvent)("FINAL_REVIEW_STARTED", debugOptions.traceId),
|
|
244
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.FINAL_REVIEW,
|
|
245
|
+
eventFlowStatus: "STARTED",
|
|
246
|
+
eventFlowTraceId: finalReviewEventFlowTraceId,
|
|
247
|
+
llmPrompt: systemPrompt,
|
|
248
|
+
});
|
|
249
|
+
// TODO: In the future, when using structured output isn't guarenteed, we will
|
|
250
|
+
// need to add a custom type guard to ensure that output is in the right shape.
|
|
251
|
+
const output = await getStructuredOutputFromLlm(systemPrompt, options.openAI, schema, undefined, tokensUsed, debugOptions && {
|
|
252
|
+
...debugOptions,
|
|
253
|
+
triggeringEventFlowName: debugEvents_js_1.EventFlowDebugNames.FINAL_REVIEW,
|
|
254
|
+
eventFlowTraceId: finalReviewEventFlowTraceId,
|
|
255
|
+
});
|
|
256
|
+
debugOptions?.eventLogHandler?.({
|
|
257
|
+
...(0, debugEvents_js_1.generateDebugEvent)("FINAL_REVIEW_COMPLETED", debugOptions.traceId),
|
|
258
|
+
eventFlowName: debugEvents_js_1.EventFlowDebugNames.FINAL_REVIEW,
|
|
259
|
+
eventFlowStatus: "COMPLETED",
|
|
260
|
+
eventFlowTraceId: finalReviewEventFlowTraceId,
|
|
261
|
+
isLlmResponseValid: output !== undefined,
|
|
262
|
+
didLlmAccomplishGoal: output?.goalAccomplished,
|
|
263
|
+
});
|
|
264
|
+
return output;
|
|
172
265
|
}
|
|
173
266
|
let edit = await getNextEdit();
|
|
174
267
|
while (edit !== undefined) {
|
|
@@ -185,7 +278,7 @@ async function* generateEdits(options, simpleSchema, idGenerator, editLog, token
|
|
|
185
278
|
/**
|
|
186
279
|
* Calls the LLM to generate a structured output response based on the provided prompt.
|
|
187
280
|
*/
|
|
188
|
-
async function getStructuredOutputFromLlm(prompt, openAi, structuredOutputSchema, description, tokensUsed) {
|
|
281
|
+
async function getStructuredOutputFromLlm(prompt, openAi, structuredOutputSchema, description, tokensUsed, debugOptions) {
|
|
189
282
|
const response_format = (0, zod_1.zodResponseFormat)(structuredOutputSchema, "SharedTreeAI", {
|
|
190
283
|
description,
|
|
191
284
|
});
|
|
@@ -195,23 +288,52 @@ async function getStructuredOutputFromLlm(prompt, openAi, structuredOutputSchema
|
|
|
195
288
|
response_format,
|
|
196
289
|
};
|
|
197
290
|
const result = await openAi.client.beta.chat.completions.parse(body);
|
|
291
|
+
debugOptions?.eventLogHandler?.({
|
|
292
|
+
...(0, debugEvents_js_1.generateDebugEvent)("LLM_API_CALL", debugOptions.traceId),
|
|
293
|
+
triggeringEventFlowName: debugOptions.triggeringEventFlowName,
|
|
294
|
+
eventFlowTraceId: debugOptions.eventFlowTraceId,
|
|
295
|
+
modelName: openAi.modelName ?? "gpt-4o",
|
|
296
|
+
requestParams: body,
|
|
297
|
+
response: { ...result },
|
|
298
|
+
...(result.usage && {
|
|
299
|
+
tokenUsage: {
|
|
300
|
+
promptTokens: result.usage.prompt_tokens,
|
|
301
|
+
completionTokens: result.usage.completion_tokens,
|
|
302
|
+
},
|
|
303
|
+
}),
|
|
304
|
+
});
|
|
198
305
|
if (result.usage !== undefined && tokensUsed !== undefined) {
|
|
199
306
|
tokensUsed.inputTokens += result.usage?.prompt_tokens;
|
|
200
307
|
tokensUsed.outputTokens += result.usage?.completion_tokens;
|
|
201
308
|
}
|
|
202
309
|
// TODO: fix types so this isn't null and doesn't need a cast
|
|
203
310
|
// The type should be derived from the zod schema
|
|
311
|
+
// TODO: Determine why this value would be undefined.
|
|
204
312
|
return result.choices[0]?.message.parsed;
|
|
205
313
|
}
|
|
206
314
|
/**
|
|
207
315
|
* Calls the LLM to generate a response based on the provided prompt.
|
|
208
316
|
*/
|
|
209
|
-
async function getStringFromLlm(prompt, openAi, tokensUsed) {
|
|
317
|
+
async function getStringFromLlm(prompt, openAi, tokensUsed, debugOptions) {
|
|
210
318
|
const body = {
|
|
211
319
|
messages: [{ role: "system", content: prompt }],
|
|
212
320
|
model: openAi.modelName ?? "gpt-4o",
|
|
213
321
|
};
|
|
214
322
|
const result = await openAi.client.chat.completions.create(body);
|
|
323
|
+
debugOptions?.eventLogHandler?.({
|
|
324
|
+
...(0, debugEvents_js_1.generateDebugEvent)("LLM_API_CALL", debugOptions.traceId),
|
|
325
|
+
triggeringEventFlowName: debugOptions.triggeringEventFlowName,
|
|
326
|
+
eventFlowTraceId: debugOptions.eventFlowTraceId,
|
|
327
|
+
modelName: openAi.modelName ?? "gpt-4o",
|
|
328
|
+
requestParams: body,
|
|
329
|
+
response: { ...result },
|
|
330
|
+
...(result.usage && {
|
|
331
|
+
tokenUsage: {
|
|
332
|
+
promptTokens: result.usage.prompt_tokens,
|
|
333
|
+
completionTokens: result.usage.completion_tokens,
|
|
334
|
+
},
|
|
335
|
+
}),
|
|
336
|
+
});
|
|
215
337
|
if (result.usage !== undefined && tokensUsed !== undefined) {
|
|
216
338
|
tokensUsed.inputTokens += result.usage?.prompt_tokens;
|
|
217
339
|
tokensUsed.outputTokens += result.usage?.completion_tokens;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/explicit-strategy/index.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tgetSimpleSchema,\n\tTree,\n\ttype SimpleTreeSchema,\n\ttype TreeNode,\n} from \"@fluidframework/tree/internal\";\n// eslint-disable-next-line import/no-internal-modules\nimport { zodResponseFormat } from \"openai/helpers/zod\";\nimport type {\n\tChatCompletionCreateParams,\n\t// eslint-disable-next-line import/no-internal-modules\n} from \"openai/resources/index.mjs\";\nimport { z } from \"zod\";\n\nimport type { OpenAiClientOptions, TokenLimits, TokenUsage } from \"../aiCollabApi.js\";\n\nimport { applyAgentEdit } from \"./agentEditReducer.js\";\nimport type { EditWrapper, TreeEdit } from \"./agentEditTypes.js\";\nimport { IdGenerator } from \"./idGenerator.js\";\nimport {\n\tgetEditingSystemPrompt,\n\tgetPlanningSystemPrompt,\n\tgetReviewSystemPrompt,\n\ttoDecoratedJson,\n\ttype EditLog,\n} from \"./promptGeneration.js\";\nimport { generateGenericEditTypes } from \"./typeGeneration.js\";\nimport { fail } from \"./utils.js\";\n\nconst DEBUG_LOG: string[] = [];\n\n/**\n * {@link generateTreeEdits} options.\n *\n * @internal\n */\nexport interface GenerateTreeEditsOptions {\n\topenAI: OpenAiClientOptions;\n\ttreeNode: TreeNode;\n\tprompt: {\n\t\tsystemRoleContext: string;\n\t\tuserAsk: string;\n\t};\n\tlimiters?: {\n\t\tabortController?: AbortController;\n\t\tmaxSequentialErrors?: number;\n\t\tmaxModelCalls?: number;\n\t\ttokenLimits?: TokenLimits;\n\t};\n\tfinalReviewStep?: boolean;\n\tvalidator?: (newContent: TreeNode) => void;\n\tdumpDebugLog?: boolean;\n\tplanningStep?: boolean;\n}\n\ninterface GenerateTreeEditsSuccessResponse {\n\tstatus: \"success\";\n\ttokensUsed: TokenUsage;\n}\n\ninterface GenerateTreeEditsErrorResponse {\n\tstatus: \"failure\" | \"partial-failure\";\n\terrorMessage: \"tokenLimitExceeded\" | \"tooManyErrors\" | \"tooManyModelCalls\" | \"aborted\";\n\ttokensUsed: TokenUsage;\n}\n\n/**\n * Prompts the provided LLM client to generate valid tree edits.\n * Applies those edits to the provided tree branch before returning.\n *\n * @remarks\n * - Optional root nodes are not supported\n * - Primitive root nodes are not supported\n *\n * @internal\n */\nexport async function generateTreeEdits(\n\toptions: GenerateTreeEditsOptions,\n): Promise<GenerateTreeEditsSuccessResponse | GenerateTreeEditsErrorResponse> {\n\tconst idGenerator = new IdGenerator();\n\tconst editLog: EditLog = [];\n\tlet editCount = 0;\n\tlet sequentialErrorCount = 0;\n\n\tconst simpleSchema = getSimpleSchema(Tree.schema(options.treeNode));\n\n\tconst tokensUsed = { inputTokens: 0, outputTokens: 0 };\n\n\ttry {\n\t\tfor await (const edit of generateEdits(\n\t\t\toptions,\n\t\t\tsimpleSchema,\n\t\t\tidGenerator,\n\t\t\teditLog,\n\t\t\toptions.limiters?.tokenLimits,\n\t\t\ttokensUsed,\n\t\t)) {\n\t\t\ttry {\n\t\t\t\tconst result = applyAgentEdit(\n\t\t\t\t\tedit,\n\t\t\t\t\tidGenerator,\n\t\t\t\t\tsimpleSchema.definitions,\n\t\t\t\t\toptions.validator,\n\t\t\t\t);\n\t\t\t\tconst explanation = result.explanation;\n\t\t\t\teditLog.push({ edit: { ...result, explanation } });\n\t\t\t\tsequentialErrorCount = 0;\n\t\t\t} catch (error: unknown) {\n\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\tsequentialErrorCount += 1;\n\t\t\t\t\teditLog.push({ edit, error: error.message });\n\t\t\t\t\tDEBUG_LOG?.push(`Error: ${error.message}`);\n\t\t\t\t} else {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst responseStatus =\n\t\t\t\teditCount > 0 && sequentialErrorCount < editCount ? \"partial-failure\" : \"failure\";\n\n\t\t\tif (options.limiters?.abortController?.signal.aborted === true) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: responseStatus,\n\t\t\t\t\terrorMessage: \"aborted\",\n\t\t\t\t\ttokensUsed,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tsequentialErrorCount >\n\t\t\t\t(options.limiters?.maxSequentialErrors ?? Number.POSITIVE_INFINITY)\n\t\t\t) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: responseStatus,\n\t\t\t\t\terrorMessage: \"tooManyErrors\",\n\t\t\t\t\ttokensUsed,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (++editCount >= (options.limiters?.maxModelCalls ?? Number.POSITIVE_INFINITY)) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: responseStatus,\n\t\t\t\t\terrorMessage: \"tooManyModelCalls\",\n\t\t\t\t\ttokensUsed,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t} catch (error: unknown) {\n\t\tif (error instanceof Error) {\n\t\t\tDEBUG_LOG?.push(`Error: ${error.message}`);\n\t\t}\n\n\t\tif (options.dumpDebugLog ?? false) {\n\t\t\tconsole.log(DEBUG_LOG.join(\"\\n\\n\"));\n\t\t\tDEBUG_LOG.length = 0;\n\t\t}\n\n\t\tif (error instanceof TokenLimitExceededError) {\n\t\t\treturn {\n\t\t\t\tstatus:\n\t\t\t\t\teditCount > 0 && sequentialErrorCount < editCount ? \"partial-failure\" : \"failure\",\n\t\t\t\terrorMessage: \"tokenLimitExceeded\",\n\t\t\t\ttokensUsed,\n\t\t\t};\n\t\t}\n\t\tthrow error;\n\t}\n\n\tif (options.dumpDebugLog ?? false) {\n\t\tconsole.log(DEBUG_LOG.join(\"\\n\\n\"));\n\t\tDEBUG_LOG.length = 0;\n\t}\n\n\treturn {\n\t\tstatus: \"success\",\n\t\ttokensUsed,\n\t};\n}\n\ninterface ReviewResult {\n\tgoalAccomplished: \"yes\" | \"no\";\n}\n\n/**\n * Generates a single {@link TreeEdit} from an LLM.\n *\n * @remarks\n * The design of this async generator function is such that which each iteration of this functions values,\n * an LLM will be prompted to generate the next value (a {@link TreeEdit}) based on the users ask.\n * Once the LLM believes it has completed the user's ask, it will no longer return an edit and as a result\n * this generator will no longer yield a next value.\n */\nasync function* generateEdits(\n\toptions: GenerateTreeEditsOptions,\n\tsimpleSchema: SimpleTreeSchema,\n\tidGenerator: IdGenerator,\n\teditLog: EditLog,\n\ttokenLimits: TokenLimits | undefined,\n\ttokensUsed: TokenUsage,\n): AsyncGenerator<TreeEdit> {\n\tconst [types, rootTypeName] = generateGenericEditTypes(simpleSchema, true);\n\n\tlet plan: string | undefined;\n\tif (options.planningStep !== undefined) {\n\t\tconst planningPromt = getPlanningSystemPrompt(\n\t\t\toptions.treeNode,\n\t\t\toptions.prompt.userAsk,\n\t\t\toptions.prompt.systemRoleContext,\n\t\t);\n\t\tDEBUG_LOG?.push(planningPromt);\n\t\tplan = await getStringFromLlm(planningPromt, options.openAI, tokensUsed);\n\t\tDEBUG_LOG?.push(`AI Generated the following plan: ${planningPromt}`);\n\t}\n\n\tconst originalDecoratedJson =\n\t\t(options.finalReviewStep ?? false)\n\t\t\t? toDecoratedJson(idGenerator, options.treeNode)\n\t\t\t: undefined;\n\t// reviewed is implicitly true if finalReviewStep is false\n\tlet hasReviewed = (options.finalReviewStep ?? false) ? false : true;\n\tasync function getNextEdit(): Promise<TreeEdit | undefined> {\n\t\tconst systemPrompt = getEditingSystemPrompt(\n\t\t\toptions.prompt.userAsk,\n\t\t\tidGenerator,\n\t\t\toptions.treeNode,\n\t\t\teditLog,\n\t\t\toptions.prompt.systemRoleContext,\n\t\t\tplan,\n\t\t);\n\n\t\tDEBUG_LOG?.push(systemPrompt);\n\n\t\tconst schema = types[rootTypeName] ?? fail(\"Root type not found.\");\n\t\tconst wrapper = await getStructuredOutputFromLlm<EditWrapper>(\n\t\t\tsystemPrompt,\n\t\t\toptions.openAI,\n\t\t\tschema,\n\t\t\t\"A JSON object that represents an edit to a JSON tree.\",\n\t\t\ttokensUsed,\n\t\t);\n\n\t\t// eslint-disable-next-line unicorn/no-null\n\t\tDEBUG_LOG?.push(JSON.stringify(wrapper, null, 2));\n\t\tif (wrapper === undefined) {\n\t\t\tDEBUG_LOG?.push(\"Failed to get response\");\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (wrapper.edit === null) {\n\t\t\tDEBUG_LOG?.push(\"No more edits.\");\n\t\t\tif ((options.finalReviewStep ?? false) && !hasReviewed) {\n\t\t\t\tconst reviewResult = await reviewGoal();\n\t\t\t\tif (reviewResult === undefined) {\n\t\t\t\t\tDEBUG_LOG?.push(\"Failed to get review response\");\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\t// eslint-disable-next-line require-atomic-updates\n\t\t\t\thasReviewed = true;\n\t\t\t\tif (reviewResult.goalAccomplished === \"yes\") {\n\t\t\t\t\treturn undefined;\n\t\t\t\t} else {\n\t\t\t\t\t// eslint-disable-next-line require-atomic-updates\n\t\t\t\t\teditLog.length = 0;\n\t\t\t\t\treturn getNextEdit();\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\treturn wrapper.edit;\n\t\t}\n\t}\n\n\tasync function reviewGoal(): Promise<ReviewResult | undefined> {\n\t\tconst systemPrompt = getReviewSystemPrompt(\n\t\t\toptions.prompt.userAsk,\n\t\t\tidGenerator,\n\t\t\toptions.treeNode,\n\t\t\toriginalDecoratedJson ?? fail(\"Original decorated tree not provided.\"),\n\t\t\toptions.prompt.systemRoleContext,\n\t\t);\n\n\t\tDEBUG_LOG?.push(systemPrompt);\n\n\t\tconst schema = z.object({\n\t\t\tgoalAccomplished: z\n\t\t\t\t.enum([\"yes\", \"no\"])\n\t\t\t\t.describe('Whether the user\\'s goal was met in the \"after\" tree.'),\n\t\t});\n\t\treturn getStructuredOutputFromLlm<ReviewResult>(systemPrompt, options.openAI, schema);\n\t}\n\n\tlet edit = await getNextEdit();\n\twhile (edit !== undefined) {\n\t\tyield edit;\n\t\tif (tokensUsed.inputTokens > (tokenLimits?.inputTokens ?? Number.POSITIVE_INFINITY)) {\n\t\t\tthrow new TokenLimitExceededError(\"Input token limit exceeded.\");\n\t\t}\n\t\tif (tokensUsed.outputTokens > (tokenLimits?.outputTokens ?? Number.POSITIVE_INFINITY)) {\n\t\t\tthrow new TokenLimitExceededError(\"Output token limit exceeded.\");\n\t\t}\n\t\tedit = await getNextEdit();\n\t}\n}\n\n/**\n * Calls the LLM to generate a structured output response based on the provided prompt.\n */\nasync function getStructuredOutputFromLlm<T>(\n\tprompt: string,\n\topenAi: OpenAiClientOptions,\n\tstructuredOutputSchema: Zod.ZodTypeAny,\n\tdescription?: string,\n\ttokensUsed?: TokenUsage,\n): Promise<T | undefined> {\n\tconst response_format = zodResponseFormat(structuredOutputSchema, \"SharedTreeAI\", {\n\t\tdescription,\n\t});\n\n\tconst body: ChatCompletionCreateParams = {\n\t\tmessages: [{ role: \"system\", content: prompt }],\n\t\tmodel: openAi.modelName ?? \"gpt-4o\",\n\t\tresponse_format,\n\t};\n\n\tconst result = await openAi.client.beta.chat.completions.parse(body);\n\n\tif (result.usage !== undefined && tokensUsed !== undefined) {\n\t\ttokensUsed.inputTokens += result.usage?.prompt_tokens;\n\t\ttokensUsed.outputTokens += result.usage?.completion_tokens;\n\t}\n\n\t// TODO: fix types so this isn't null and doesn't need a cast\n\t// The type should be derived from the zod schema\n\treturn result.choices[0]?.message.parsed as T | undefined;\n}\n\n/**\n * Calls the LLM to generate a response based on the provided prompt.\n */\nasync function getStringFromLlm(\n\tprompt: string,\n\topenAi: OpenAiClientOptions,\n\ttokensUsed?: TokenUsage,\n): Promise<string | undefined> {\n\tconst body: ChatCompletionCreateParams = {\n\t\tmessages: [{ role: \"system\", content: prompt }],\n\t\tmodel: openAi.modelName ?? \"gpt-4o\",\n\t};\n\n\tconst result = await openAi.client.chat.completions.create(body);\n\n\tif (result.usage !== undefined && tokensUsed !== undefined) {\n\t\ttokensUsed.inputTokens += result.usage?.prompt_tokens;\n\t\ttokensUsed.outputTokens += result.usage?.completion_tokens;\n\t}\n\n\treturn result.choices[0]?.message.content ?? undefined;\n}\n\nclass TokenLimitExceededError extends Error {}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/explicit-strategy/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,uEAAsE;AACtE,4DAKuC;AACvC,sDAAsD;AACtD,4CAAuD;AAKvD,+BAAoC;AACpC,6BAAwB;AASxB,+DAAuD;AAEvD,qDAe0B;AAC1B,qDAA+C;AAC/C,+DAM+B;AAC/B,2DAA+D;AAC/D,yCAAkC;AA4DlC;;;;;;;;;GASG;AACI,KAAK,UAAU,iBAAiB,CACtC,OAAiC;IAEjC,MAAM,WAAW,GAAG,IAAI,4BAAW,EAAE,CAAC;IACtC,MAAM,OAAO,GAAY,EAAE,CAAC;IAC5B,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,oBAAoB,GAAG,CAAC,CAAC;IAE7B,MAAM,YAAY,GAAG,IAAA,0BAAe,EAAC,eAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEpE,MAAM,UAAU,GAAG,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;IAEvD,MAAM,eAAe,GAAG,IAAA,SAAM,GAAE,CAAC;IAEjC,MAAM,oBAAoB,GAAG,IAAA,SAAM,GAAE,CAAC;IACtC,OAAO,CAAC,oBAAoB,EAAE,CAAC;QAC9B,GAAG,IAAA,mCAAkB,EAAC,yBAAyB,EAAE,eAAe,CAAC;QACjE,aAAa,EAAE,oCAAmB,CAAC,eAAe;QAClD,eAAe,EAAE,SAAS;QAC1B,gBAAgB,EAAE,oBAAoB;KACP,CAAC,CAAC;IAElC,IAAI,CAAC;QACJ,IAAI,KAAK,EAAE,MAAM,kBAAkB,IAAI,aAAa,CACnD,OAAO,EACP,YAAY,EACZ,WAAW,EACX,OAAO,EACP,OAAO,CAAC,QAAQ,EAAE,WAAW,EAC7B,UAAU,EACV,OAAO,CAAC,oBAAoB,IAAI;YAC/B,eAAe,EAAE,OAAO,CAAC,oBAAoB;YAC7C,OAAO,EAAE,eAAe;SACxB,CACD,EAAE,CAAC;YACH,IAAI,CAAC;gBACJ,MAAM,MAAM,GAAG,IAAA,oCAAc,EAC5B,kBAAkB,CAAC,IAAI,EACvB,WAAW,EACX,YAAY,CAAC,WAAW,EACxB,OAAO,CAAC,SAAS,CACjB,CAAC;gBACF,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;gBACvC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,MAAM,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;gBACnD,oBAAoB,GAAG,CAAC,CAAC;gBAEzB,OAAO,CAAC,oBAAoB,EAAE,CAAC;oBAC9B,GAAG,IAAA,mCAAkB,EAAC,sBAAsB,EAAE,eAAe,CAAC;oBAC9D,aAAa,EAAE,oCAAmB,CAAC,4BAA4B;oBAC/D,eAAe,EAAE,aAAa;oBAC9B,gBAAgB,EAAE,kBAAkB,CAAC,gBAAgB;oBACrD,IAAI,EAAE,kBAAkB,CAAC,IAA0C;iBACxC,CAAC,CAAC;YAC/B,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACzB,OAAO,CAAC,oBAAoB,EAAE,CAAC;oBAC9B,GAAG,IAAA,mCAAkB,EAAC,sBAAsB,EAAE,eAAe,CAAC;oBAC9D,aAAa,EAAE,oCAAmB,CAAC,4BAA4B;oBAC/D,eAAe,EAAE,aAAa;oBAC9B,gBAAgB,EAAE,kBAAkB,CAAC,gBAAgB;oBACrD,IAAI,EAAE,kBAAkB,CAAC,IAA0C;oBACnE,YAAY,EAAG,KAAe,EAAE,OAAO;oBACvC,oBAAoB;iBACO,CAAC,CAAC;gBAE9B,IAAI,KAAK,YAAY,qBAAU,EAAE,CAAC;oBACjC,oBAAoB,IAAI,CAAC,CAAC;oBAC1B,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAAkB,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBACvE,CAAC;qBAAM,CAAC;oBACP,MAAM,KAAK,CAAC;gBACb,CAAC;YACF,CAAC;YAED,IAAI,eAAe,GAAG,KAAK,CAAC;YAC5B,MAAM,kBAAkB,GAAmC;gBAC1D,MAAM,EACL,SAAS,GAAG,CAAC,IAAI,oBAAoB,GAAG,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS;gBAClF,YAAY,EAAE,iBAAiB;gBAC/B,UAAU;aACV,CAAC;YAEF,IAAI,OAAO,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;gBAChE,kBAAkB,CAAC,YAAY,GAAG,SAAS,CAAC;gBAC5C,eAAe,GAAG,IAAI,CAAC;YACxB,CAAC;iBAAM,IACN,oBAAoB;gBACpB,CAAC,OAAO,CAAC,QAAQ,EAAE,mBAAmB,IAAI,MAAM,CAAC,iBAAiB,CAAC,EAClE,CAAC;gBACF,kBAAkB,CAAC,YAAY,GAAG,eAAe,CAAC;gBAClD,eAAe,GAAG,IAAI,CAAC;YACxB,CAAC;iBAAM,IACN,EAAE,SAAS,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,aAAa,IAAI,MAAM,CAAC,iBAAiB,CAAC,EAC3E,CAAC;gBACF,kBAAkB,CAAC,YAAY,GAAG,mBAAmB,CAAC;gBACtD,eAAe,GAAG,IAAI,CAAC;YACxB,CAAC;YAED,IAAI,eAAe,EAAE,CAAC;gBACrB,OAAO,CAAC,oBAAoB,EAAE,CAAC;oBAC9B,GAAG,IAAA,mCAAkB,EAAC,2BAA2B,EAAE,eAAe,CAAC;oBACnE,aAAa,EAAE,oCAAmB,CAAC,eAAe;oBAClD,eAAe,EAAE,WAAW;oBAC5B,MAAM,EAAE,SAAS;oBACjB,aAAa,EAAE,kBAAkB,CAAC,YAAY;oBAC9C,gBAAgB,EAAE,oBAAoB;iBACL,CAAC,CAAC;gBAEpC,OAAO,kBAAkB,CAAC;YAC3B,CAAC;QACF,CAAC;IACF,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACzB,OAAO,CAAC,oBAAoB,EAAE,CAAC;YAC9B,GAAG,IAAA,mCAAkB,EAAC,2BAA2B,EAAE,eAAe,CAAC;YACnE,aAAa,EAAE,oCAAmB,CAAC,eAAe;YAClD,eAAe,EAAE,WAAW;YAC5B,MAAM,EAAE,SAAS;YACjB,gBAAgB,EAAE,oBAAoB;YACtC,aAAa,EACZ,KAAK,YAAY,uBAAuB,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,iBAAiB;YACpF,YAAY,EAAG,KAAe,EAAE,OAAO;SACN,CAAC,CAAC;QAEpC,IAAI,KAAK,YAAY,uBAAuB,EAAE,CAAC;YAC9C,OAAO;gBACN,MAAM,EACL,SAAS,GAAG,CAAC,IAAI,oBAAoB,GAAG,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS;gBAClF,YAAY,EAAE,oBAAoB;gBAClC,UAAU;aACV,CAAC;QACH,CAAC;QACD,MAAM,KAAK,CAAC;IACb,CAAC;IAED,OAAO,CAAC,oBAAoB,EAAE,CAAC;QAC9B,GAAG,IAAA,mCAAkB,EAAC,2BAA2B,EAAE,eAAe,CAAC;QACnE,aAAa,EAAE,oCAAmB,CAAC,eAAe;QAClD,eAAe,EAAE,WAAW;QAC5B,gBAAgB,EAAE,oBAAoB;QACtC,MAAM,EAAE,SAAS;KACgB,CAAC,CAAC;IAEpC,OAAO;QACN,MAAM,EAAE,SAAS;QACjB,UAAU;KACV,CAAC;AACH,CAAC;AAhJD,8CAgJC;AAMD;;;;;;;;GAQG;AACH,KAAK,SAAS,CAAC,CAAC,aAAa,CAC5B,OAAiC,EACjC,YAA8B,EAC9B,WAAwB,EACxB,OAAgB,EAChB,WAAoC,EACpC,UAAsB,EACtB,YAGC;IAED,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC,GAAG,IAAA,4CAAwB,EAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAE3E,IAAI,IAAwB,CAAC;IAC7B,IAAI,OAAO,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACxC,MAAM,cAAc,GAAG,IAAA,6CAAuB,EAC7C,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,MAAM,CAAC,OAAO,EACtB,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAChC,CAAC;QAEF,MAAM,iCAAiC,GAAG,IAAA,SAAM,GAAE,CAAC;QACnD,YAAY,EAAE,eAAe,EAAE,CAAC;YAC/B,GAAG,IAAA,mCAAkB,EAAC,kCAAkC,EAAE,YAAY,CAAC,OAAO,CAAC;YAC/E,aAAa,EAAE,oCAAmB,CAAC,wBAAwB;YAC3D,gBAAgB,EAAE,iCAAiC;YACnD,eAAe,EAAE,SAAS;SACM,CAAC,CAAC;QAEnC,IAAI,GAAG,MAAM,gBAAgB,CAC5B,cAAc,EACd,OAAO,CAAC,MAAM,EACd,UAAU,EACV,YAAY,IAAI;YACf,GAAG,YAAY;YACf,uBAAuB,EAAE,oCAAmB,CAAC,wBAAwB;YACrE,gBAAgB,EAAE,iCAAiC;SACnD,CACD,CAAC;QAEF,YAAY,EAAE,eAAe,EAAE,CAAC;YAC/B,GAAG,IAAA,mCAAkB,EAAC,oCAAoC,EAAE,YAAY,CAAC,OAAO,CAAC;YACjF,aAAa,EAAE,oCAAmB,CAAC,wBAAwB;YAC3D,eAAe,EAAE,WAAW;YAC5B,gBAAgB,EAAE,iCAAiC;YACnD,kBAAkB,EAAE,IAAI,KAAK,SAAS;YACtC,gBAAgB,EAAE,IAAI;SACY,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,qBAAqB,GAC1B,CAAC,OAAO,CAAC,eAAe,IAAI,KAAK,CAAC;QACjC,CAAC,CAAC,IAAA,qCAAe,EAAC,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC;QAChD,CAAC,CAAC,SAAS,CAAC;IACd,0DAA0D;IAC1D,IAAI,WAAW,GAAG,CAAC,OAAO,CAAC,eAAe,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACpE,KAAK,UAAU,WAAW;QAGzB,MAAM,YAAY,GAAG,IAAA,4CAAsB,EAC1C,OAAO,CAAC,MAAM,CAAC,OAAO,EACtB,WAAW,EACX,OAAO,CAAC,QAAQ,EAChB,OAAO,EACP,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAChC,IAAI,CACJ,CAAC;QAEF,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,IAAA,eAAI,EAAC,sBAAsB,CAAC,CAAC;QAEnE,MAAM,2BAA2B,GAAG,IAAA,SAAM,GAAE,CAAC;QAC7C,YAAY,EAAE,eAAe,EAAE,CAAC;YAC/B,GAAG,IAAA,mCAAkB,EAAC,4BAA4B,EAAE,YAAY,CAAC,OAAO,CAAC;YACzE,aAAa,EAAE,oCAAmB,CAAC,4BAA4B;YAC/D,eAAe,EAAE,SAAS;YAC1B,gBAAgB,EAAE,2BAA2B;YAC7C,SAAS,EAAE,YAAY;SACW,CAAC,CAAC;QAErC,MAAM,OAAO,GAAG,MAAM,0BAA0B,CAC/C,YAAY,EACZ,OAAO,CAAC,MAAM,EACd,MAAM,EACN,uDAAuD,EACvD,UAAU,EACV,YAAY,IAAI;YACf,GAAG,YAAY;YACf,uBAAuB,EAAE,oCAAmB,CAAC,4BAA4B;YACzE,gBAAgB,EAAE,2BAA2B;SAC7C,CACD,CAAC;QAEF,YAAY,EAAE,eAAe,EAAE,CAAC;YAC/B,GAAG,IAAA,mCAAkB,EAAC,8BAA8B,EAAE,YAAY,CAAC,OAAO,CAAC;YAC3E,aAAa,EAAE,oCAAmB,CAAC,4BAA4B;YAC/D,eAAe,EAAE,WAAW;YAC5B,gBAAgB,EAAE,2BAA2B;YAC7C,kBAAkB,EAAE,OAAO,EAAE,IAAI,KAAK,SAAS;YAC/C,gBAAgB,EAAE,OAAO,EAAE,IAAsC;SAC7B,CAAC,CAAC;QAEvC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,OAAO,CAAC,eAAe,IAAI,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACxD,MAAM,YAAY,GAAG,MAAM,UAAU,EAAE,CAAC;gBACxC,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;oBAChC,OAAO,SAAS,CAAC;gBAClB,CAAC;gBACD,kDAAkD;gBAClD,WAAW,GAAG,IAAI,CAAC;gBACnB,IAAI,YAAY,CAAC,gBAAgB,KAAK,KAAK,EAAE,CAAC;oBAC7C,OAAO,SAAS,CAAC;gBAClB,CAAC;qBAAM,CAAC;oBACP,kDAAkD;oBAClD,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;oBACnB,OAAO,WAAW,EAAE,CAAC;gBACtB,CAAC;YACF,CAAC;QACF,CAAC;aAAM,CAAC;YACP,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,CAAC;QAC9E,CAAC;IACF,CAAC;IAED,KAAK,UAAU,UAAU;QACxB,MAAM,YAAY,GAAG,IAAA,2CAAqB,EACzC,OAAO,CAAC,MAAM,CAAC,OAAO,EACtB,WAAW,EACX,OAAO,CAAC,QAAQ,EAChB,qBAAqB,IAAI,IAAA,eAAI,EAAC,uCAAuC,CAAC,EACtE,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAChC,CAAC;QAEF,MAAM,MAAM,GAAG,OAAC,CAAC,MAAM,CAAC;YACvB,gBAAgB,EAAE,OAAC;iBACjB,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;iBACnB,QAAQ,CAAC,uDAAuD,CAAC;SACnE,CAAC,CAAC;QAEH,MAAM,2BAA2B,GAAG,IAAA,SAAM,GAAE,CAAC;QAC7C,YAAY,EAAE,eAAe,EAAE,CAAC;YAC/B,GAAG,IAAA,mCAAkB,EAAC,sBAAsB,EAAE,YAAY,CAAC,OAAO,CAAC;YACnE,aAAa,EAAE,oCAAmB,CAAC,YAAY;YAC/C,eAAe,EAAE,SAAS;YAC1B,gBAAgB,EAAE,2BAA2B;YAC7C,SAAS,EAAE,YAAY;SACM,CAAC,CAAC;QAEhC,8EAA8E;QAC9E,+EAA+E;QAC/E,MAAM,MAAM,GAAG,MAAM,0BAA0B,CAC9C,YAAY,EACZ,OAAO,CAAC,MAAM,EACd,MAAM,EACN,SAAS,EACT,UAAU,EACV,YAAY,IAAI;YACf,GAAG,YAAY;YACf,uBAAuB,EAAE,oCAAmB,CAAC,YAAY;YACzD,gBAAgB,EAAE,2BAA2B;SAC7C,CACD,CAAC;QAEF,YAAY,EAAE,eAAe,EAAE,CAAC;YAC/B,GAAG,IAAA,mCAAkB,EAAC,wBAAwB,EAAE,YAAY,CAAC,OAAO,CAAC;YACrE,aAAa,EAAE,oCAAmB,CAAC,YAAY;YAC/C,eAAe,EAAE,WAAW;YAC5B,gBAAgB,EAAE,2BAA2B;YAC7C,kBAAkB,EAAE,MAAM,KAAK,SAAS;YACxC,oBAAoB,EAAE,MAAM,EAAE,gBAAgB;SACf,CAAC,CAAC;QAElC,OAAO,MAAM,CAAC;IACf,CAAC;IAED,IAAI,IAAI,GAAG,MAAM,WAAW,EAAE,CAAC;IAC/B,OAAO,IAAI,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,CAAC;QACX,IAAI,UAAU,CAAC,WAAW,GAAG,CAAC,WAAW,EAAE,WAAW,IAAI,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACrF,MAAM,IAAI,uBAAuB,CAAC,6BAA6B,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,UAAU,CAAC,YAAY,GAAG,CAAC,WAAW,EAAE,YAAY,IAAI,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACvF,MAAM,IAAI,uBAAuB,CAAC,8BAA8B,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,GAAG,MAAM,WAAW,EAAE,CAAC;IAC5B,CAAC;AACF,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,0BAA0B,CACxC,MAAc,EACd,MAA2B,EAC3B,sBAAsC,EACtC,WAAoB,EACpB,UAAuB,EACvB,YAKC;IAED,MAAM,eAAe,GAAG,IAAA,uBAAiB,EAAC,sBAAsB,EAAE,cAAc,EAAE;QACjF,WAAW;KACX,CAAC,CAAC;IAEH,MAAM,IAAI,GAA+B;QACxC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAC/C,KAAK,EAAE,MAAM,CAAC,SAAS,IAAI,QAAQ;QACnC,eAAe;KACf,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAErE,YAAY,EAAE,eAAe,EAAE,CAAC;QAC/B,GAAG,IAAA,mCAAkB,EAAC,cAAc,EAAE,YAAY,CAAC,OAAO,CAAC;QAC3D,uBAAuB,EAAE,YAAY,CAAC,uBAAuB;QAC7D,gBAAgB,EAAE,YAAY,CAAC,gBAAgB;QAC/C,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,QAAQ;QACvC,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,EAAE,GAAG,MAAM,EAAE;QACvB,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI;YACnB,UAAU,EAAE;gBACX,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,aAAa;gBACxC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,iBAAiB;aAChD;SACD,CAAC;KAC6B,CAAC,CAAC;IAElC,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC5D,UAAU,CAAC,WAAW,IAAI,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC;QACtD,UAAU,CAAC,YAAY,IAAI,MAAM,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAC5D,CAAC;IAED,6DAA6D;IAC7D,iDAAiD;IACjD,qDAAqD;IACrD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,MAAuB,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAC9B,MAAc,EACd,MAA2B,EAC3B,UAAuB,EACvB,YAKC;IAED,MAAM,IAAI,GAA+B;QACxC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAC/C,KAAK,EAAE,MAAM,CAAC,SAAS,IAAI,QAAQ;KACnC,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEjE,YAAY,EAAE,eAAe,EAAE,CAAC;QAC/B,GAAG,IAAA,mCAAkB,EAAC,cAAc,EAAE,YAAY,CAAC,OAAO,CAAC;QAC3D,uBAAuB,EAAE,YAAY,CAAC,uBAAuB;QAC7D,gBAAgB,EAAE,YAAY,CAAC,gBAAgB;QAC/C,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,QAAQ;QACvC,aAAa,EAAE,IAAI;QACnB,QAAQ,EAAE,EAAE,GAAG,MAAM,EAAE;QACvB,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI;YACnB,UAAU,EAAE;gBACX,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,aAAa;gBACxC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,iBAAiB;aAChD;SACD,CAAC;KAC6B,CAAC,CAAC;IAElC,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC5D,UAAU,CAAC,WAAW,IAAI,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC;QACtD,UAAU,CAAC,YAAY,IAAI,MAAM,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAC5D,CAAC;IAED,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,IAAI,SAAS,CAAC;AACxD,CAAC;AAED,MAAM,uBAAwB,SAAQ,KAAK;CAAG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { UsageError } from \"@fluidframework/telemetry-utils/internal\";\nimport {\n\tgetSimpleSchema,\n\tTree,\n\ttype SimpleTreeSchema,\n\ttype TreeNode,\n} from \"@fluidframework/tree/internal\";\n// eslint-disable-next-line import/no-internal-modules\nimport { zodResponseFormat } from \"openai/helpers/zod\";\nimport type {\n\tChatCompletionCreateParams,\n\t// eslint-disable-next-line import/no-internal-modules\n} from \"openai/resources/index.mjs\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { z } from \"zod\";\n\nimport type {\n\tDebugEventLogHandler,\n\tOpenAiClientOptions,\n\tTokenLimits,\n\tTokenUsage,\n} from \"../aiCollabApi.js\";\n\nimport { applyAgentEdit } from \"./agentEditReducer.js\";\nimport type { EditWrapper, TreeEdit } from \"./agentEditTypes.js\";\nimport {\n\ttype ApplyEditFailure,\n\ttype ApplyEditSuccess,\n\ttype GenerateTreeEditCompleted,\n\ttype GenerateTreeEditStarted,\n\ttype FinalReviewCompleted,\n\ttype FinalReviewStarted,\n\ttype LlmApiCallDebugEvent,\n\ttype PlanningPromptCompleted,\n\ttype CoreEventLoopStarted,\n\ttype CoreEventLoopCompleted,\n\tgenerateDebugEvent,\n\ttype PlanningPromptStarted,\n\ttype EventFlowDebugName,\n\tEventFlowDebugNames,\n} from \"./debugEvents.js\";\nimport { IdGenerator } from \"./idGenerator.js\";\nimport {\n\tgetEditingSystemPrompt,\n\tgetPlanningSystemPrompt,\n\tgetReviewSystemPrompt,\n\ttoDecoratedJson,\n\ttype EditLog,\n} from \"./promptGeneration.js\";\nimport { generateGenericEditTypes } from \"./typeGeneration.js\";\nimport { fail } from \"./utils.js\";\n\n// TODO: Create a proper index file and move the logic of this file to a new location\nexport type {\n\tApplyEditFailure,\n\tApplyEditSuccess,\n\tCoreEventLoopCompleted,\n\tCoreEventLoopStarted,\n\tFinalReviewCompleted,\n\tFinalReviewStarted,\n\tGenerateTreeEditCompleted,\n\tGenerateTreeEditStarted,\n\tLlmApiCallDebugEvent,\n\tPlanningPromptCompleted,\n\tPlanningPromptStarted,\n\tLlmTreeEdit,\n\tEventFlowDebugName,\n\tEventFlowDebugNames,\n} from \"./debugEvents.js\";\n\n/**\n * {@link generateTreeEdits} options.\n *\n * @internal\n */\nexport interface GenerateTreeEditsOptions {\n\topenAI: OpenAiClientOptions;\n\ttreeNode: TreeNode;\n\tprompt: {\n\t\tsystemRoleContext: string;\n\t\tuserAsk: string;\n\t};\n\tlimiters?: {\n\t\tabortController?: AbortController;\n\t\tmaxSequentialErrors?: number;\n\t\tmaxModelCalls?: number;\n\t\ttokenLimits?: TokenLimits;\n\t};\n\tfinalReviewStep?: boolean;\n\tvalidator?: (newContent: TreeNode) => void;\n\tdebugEventLogHandler?: DebugEventLogHandler;\n\tplanningStep?: boolean;\n}\n\ninterface GenerateTreeEditsSuccessResponse {\n\tstatus: \"success\";\n\ttokensUsed: TokenUsage;\n}\n\ninterface GenerateTreeEditsErrorResponse {\n\tstatus: \"failure\" | \"partial-failure\";\n\terrorMessage:\n\t\t| \"tokenLimitExceeded\"\n\t\t| \"tooManyErrors\"\n\t\t| \"tooManyModelCalls\"\n\t\t| \"aborted\"\n\t\t| \"unexpectedError\";\n\ttokensUsed: TokenUsage;\n}\n\n/**\n * Prompts the provided LLM client to generate valid tree edits.\n * Applies those edits to the provided tree branch before returning.\n *\n * @remarks\n * - Optional root nodes are not supported\n * - Primitive root nodes are not supported\n *\n * @internal\n */\nexport async function generateTreeEdits(\n\toptions: GenerateTreeEditsOptions,\n): Promise<GenerateTreeEditsSuccessResponse | GenerateTreeEditsErrorResponse> {\n\tconst idGenerator = new IdGenerator();\n\tconst editLog: EditLog = [];\n\tlet editCount = 0;\n\tlet sequentialErrorCount = 0;\n\n\tconst simpleSchema = getSimpleSchema(Tree.schema(options.treeNode));\n\n\tconst tokensUsed = { inputTokens: 0, outputTokens: 0 };\n\n\tconst debugLogTraceId = uuidv4();\n\n\tconst coreEventFlowTraceId = uuidv4();\n\toptions.debugEventLogHandler?.({\n\t\t...generateDebugEvent(\"CORE_EVENT_LOOP_STARTED\", debugLogTraceId),\n\t\teventFlowName: EventFlowDebugNames.CORE_EVENT_LOOP,\n\t\teventFlowStatus: \"STARTED\",\n\t\teventFlowTraceId: coreEventFlowTraceId,\n\t} satisfies CoreEventLoopStarted);\n\n\ttry {\n\t\tfor await (const generateEditResult of generateEdits(\n\t\t\toptions,\n\t\t\tsimpleSchema,\n\t\t\tidGenerator,\n\t\t\teditLog,\n\t\t\toptions.limiters?.tokenLimits,\n\t\t\ttokensUsed,\n\t\t\toptions.debugEventLogHandler && {\n\t\t\t\teventLogHandler: options.debugEventLogHandler,\n\t\t\t\ttraceId: debugLogTraceId,\n\t\t\t},\n\t\t)) {\n\t\t\ttry {\n\t\t\t\tconst result = applyAgentEdit(\n\t\t\t\t\tgenerateEditResult.edit,\n\t\t\t\t\tidGenerator,\n\t\t\t\t\tsimpleSchema.definitions,\n\t\t\t\t\toptions.validator,\n\t\t\t\t);\n\t\t\t\tconst explanation = result.explanation;\n\t\t\t\teditLog.push({ edit: { ...result, explanation } });\n\t\t\t\tsequentialErrorCount = 0;\n\n\t\t\t\toptions.debugEventLogHandler?.({\n\t\t\t\t\t...generateDebugEvent(\"APPLIED_EDIT_SUCCESS\", debugLogTraceId),\n\t\t\t\t\teventFlowName: EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,\n\t\t\t\t\teventFlowStatus: \"IN_PROGRESS\",\n\t\t\t\t\teventFlowTraceId: generateEditResult.eventFlowTraceId,\n\t\t\t\t\tedit: generateEditResult.edit as unknown as Record<string, unknown>,\n\t\t\t\t} satisfies ApplyEditSuccess);\n\t\t\t} catch (error: unknown) {\n\t\t\t\toptions.debugEventLogHandler?.({\n\t\t\t\t\t...generateDebugEvent(\"APPLIED_EDIT_FAILURE\", debugLogTraceId),\n\t\t\t\t\teventFlowName: EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,\n\t\t\t\t\teventFlowStatus: \"IN_PROGRESS\",\n\t\t\t\t\teventFlowTraceId: generateEditResult.eventFlowTraceId,\n\t\t\t\t\tedit: generateEditResult.edit as unknown as Record<string, unknown>,\n\t\t\t\t\terrorMessage: (error as Error)?.message,\n\t\t\t\t\tsequentialErrorCount,\n\t\t\t\t} satisfies ApplyEditFailure);\n\n\t\t\t\tif (error instanceof UsageError) {\n\t\t\t\t\tsequentialErrorCount += 1;\n\t\t\t\t\teditLog.push({ edit: generateEditResult.edit, error: error.message });\n\t\t\t\t} else {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet shouldExitEarly = false;\n\t\t\tconst completionResponse: GenerateTreeEditsErrorResponse = {\n\t\t\t\tstatus:\n\t\t\t\t\teditCount > 0 && sequentialErrorCount < editCount ? \"partial-failure\" : \"failure\",\n\t\t\t\terrorMessage: \"unexpectedError\",\n\t\t\t\ttokensUsed,\n\t\t\t};\n\n\t\t\tif (options.limiters?.abortController?.signal.aborted === true) {\n\t\t\t\tcompletionResponse.errorMessage = \"aborted\";\n\t\t\t\tshouldExitEarly = true;\n\t\t\t} else if (\n\t\t\t\tsequentialErrorCount >\n\t\t\t\t(options.limiters?.maxSequentialErrors ?? Number.POSITIVE_INFINITY)\n\t\t\t) {\n\t\t\t\tcompletionResponse.errorMessage = \"tooManyErrors\";\n\t\t\t\tshouldExitEarly = true;\n\t\t\t} else if (\n\t\t\t\t++editCount >= (options.limiters?.maxModelCalls ?? Number.POSITIVE_INFINITY)\n\t\t\t) {\n\t\t\t\tcompletionResponse.errorMessage = \"tooManyModelCalls\";\n\t\t\t\tshouldExitEarly = true;\n\t\t\t}\n\n\t\t\tif (shouldExitEarly) {\n\t\t\t\toptions.debugEventLogHandler?.({\n\t\t\t\t\t...generateDebugEvent(\"CORE_EVENT_LOOP_COMPLETED\", debugLogTraceId),\n\t\t\t\t\teventFlowName: EventFlowDebugNames.CORE_EVENT_LOOP,\n\t\t\t\t\teventFlowStatus: \"COMPLETED\",\n\t\t\t\t\tstatus: \"failure\",\n\t\t\t\t\tfailureReason: completionResponse.errorMessage,\n\t\t\t\t\teventFlowTraceId: coreEventFlowTraceId,\n\t\t\t\t} satisfies CoreEventLoopCompleted);\n\n\t\t\t\treturn completionResponse;\n\t\t\t}\n\t\t}\n\t} catch (error: unknown) {\n\t\toptions.debugEventLogHandler?.({\n\t\t\t...generateDebugEvent(\"CORE_EVENT_LOOP_COMPLETED\", debugLogTraceId),\n\t\t\teventFlowName: EventFlowDebugNames.CORE_EVENT_LOOP,\n\t\t\teventFlowStatus: \"COMPLETED\",\n\t\t\tstatus: \"failure\",\n\t\t\teventFlowTraceId: coreEventFlowTraceId,\n\t\t\tfailureReason:\n\t\t\t\terror instanceof TokenLimitExceededError ? \"tokenLimitExceeded\" : \"unexpectedError\",\n\t\t\terrorMessage: (error as Error)?.message,\n\t\t} satisfies CoreEventLoopCompleted);\n\n\t\tif (error instanceof TokenLimitExceededError) {\n\t\t\treturn {\n\t\t\t\tstatus:\n\t\t\t\t\teditCount > 0 && sequentialErrorCount < editCount ? \"partial-failure\" : \"failure\",\n\t\t\t\terrorMessage: \"tokenLimitExceeded\",\n\t\t\t\ttokensUsed,\n\t\t\t};\n\t\t}\n\t\tthrow error;\n\t}\n\n\toptions.debugEventLogHandler?.({\n\t\t...generateDebugEvent(\"CORE_EVENT_LOOP_COMPLETED\", debugLogTraceId),\n\t\teventFlowName: EventFlowDebugNames.CORE_EVENT_LOOP,\n\t\teventFlowStatus: \"COMPLETED\",\n\t\teventFlowTraceId: coreEventFlowTraceId,\n\t\tstatus: \"success\",\n\t} satisfies CoreEventLoopCompleted);\n\n\treturn {\n\t\tstatus: \"success\",\n\t\ttokensUsed,\n\t};\n}\n\ninterface ReviewResult {\n\tgoalAccomplished: \"yes\" | \"no\";\n}\n\n/**\n * Generates a single {@link TreeEdit} from an LLM.\n *\n * @remarks\n * The design of this async generator function is such that which each iteration of this functions values,\n * an LLM will be prompted to generate the next value (a {@link TreeEdit}) based on the users ask.\n * Once the LLM believes it has completed the user's ask, it will no longer return an edit and as a result\n * this generator will no longer yield a next value.\n */\nasync function* generateEdits(\n\toptions: GenerateTreeEditsOptions,\n\tsimpleSchema: SimpleTreeSchema,\n\tidGenerator: IdGenerator,\n\teditLog: EditLog,\n\ttokenLimits: TokenLimits | undefined,\n\ttokensUsed: TokenUsage,\n\tdebugOptions?: {\n\t\teventLogHandler: DebugEventLogHandler;\n\t\ttraceId: string;\n\t},\n): AsyncGenerator<{ edit: TreeEdit; eventFlowTraceId: string }> {\n\tconst [types, rootTypeName] = generateGenericEditTypes(simpleSchema, true);\n\n\tlet plan: string | undefined;\n\tif (options.planningStep !== undefined) {\n\t\tconst planningPrompt = getPlanningSystemPrompt(\n\t\t\toptions.treeNode,\n\t\t\toptions.prompt.userAsk,\n\t\t\toptions.prompt.systemRoleContext,\n\t\t);\n\n\t\tconst generatePlanningPromptEventFlowId = uuidv4();\n\t\tdebugOptions?.eventLogHandler?.({\n\t\t\t...generateDebugEvent(\"GENERATE_PLANNING_PROMPT_STARTED\", debugOptions.traceId),\n\t\t\teventFlowName: EventFlowDebugNames.GENERATE_PLANNING_PROMPT,\n\t\t\teventFlowTraceId: generatePlanningPromptEventFlowId,\n\t\t\teventFlowStatus: \"STARTED\",\n\t\t} satisfies PlanningPromptStarted);\n\n\t\tplan = await getStringFromLlm(\n\t\t\tplanningPrompt,\n\t\t\toptions.openAI,\n\t\t\ttokensUsed,\n\t\t\tdebugOptions && {\n\t\t\t\t...debugOptions,\n\t\t\t\ttriggeringEventFlowName: EventFlowDebugNames.GENERATE_PLANNING_PROMPT,\n\t\t\t\teventFlowTraceId: generatePlanningPromptEventFlowId,\n\t\t\t},\n\t\t);\n\n\t\tdebugOptions?.eventLogHandler?.({\n\t\t\t...generateDebugEvent(\"GENERATE_PLANNING_PROMPT_COMPLETED\", debugOptions.traceId),\n\t\t\teventFlowName: EventFlowDebugNames.GENERATE_PLANNING_PROMPT,\n\t\t\teventFlowStatus: \"COMPLETED\",\n\t\t\teventFlowTraceId: generatePlanningPromptEventFlowId,\n\t\t\tisLlmResponseValid: plan !== undefined,\n\t\t\tllmGeneratedPlan: plan,\n\t\t} satisfies PlanningPromptCompleted);\n\t}\n\n\tconst originalDecoratedJson =\n\t\t(options.finalReviewStep ?? false)\n\t\t\t? toDecoratedJson(idGenerator, options.treeNode)\n\t\t\t: undefined;\n\t// reviewed is implicitly true if finalReviewStep is false\n\tlet hasReviewed = (options.finalReviewStep ?? false) ? false : true;\n\tasync function getNextEdit(): Promise<\n\t\t{ edit: TreeEdit; eventFlowTraceId: string } | undefined\n\t> {\n\t\tconst systemPrompt = getEditingSystemPrompt(\n\t\t\toptions.prompt.userAsk,\n\t\t\tidGenerator,\n\t\t\toptions.treeNode,\n\t\t\teditLog,\n\t\t\toptions.prompt.systemRoleContext,\n\t\t\tplan,\n\t\t);\n\n\t\tconst schema = types[rootTypeName] ?? fail(\"Root type not found.\");\n\n\t\tconst generateTreeEditEventFlowId = uuidv4();\n\t\tdebugOptions?.eventLogHandler?.({\n\t\t\t...generateDebugEvent(\"GENERATE_TREE_EDIT_STARTED\", debugOptions.traceId),\n\t\t\teventFlowName: EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,\n\t\t\teventFlowStatus: \"STARTED\",\n\t\t\teventFlowTraceId: generateTreeEditEventFlowId,\n\t\t\tllmPrompt: systemPrompt,\n\t\t} satisfies GenerateTreeEditStarted);\n\n\t\tconst wrapper = await getStructuredOutputFromLlm<EditWrapper>(\n\t\t\tsystemPrompt,\n\t\t\toptions.openAI,\n\t\t\tschema,\n\t\t\t\"A JSON object that represents an edit to a JSON tree.\",\n\t\t\ttokensUsed,\n\t\t\tdebugOptions && {\n\t\t\t\t...debugOptions,\n\t\t\t\ttriggeringEventFlowName: EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,\n\t\t\t\teventFlowTraceId: generateTreeEditEventFlowId,\n\t\t\t},\n\t\t);\n\n\t\tdebugOptions?.eventLogHandler?.({\n\t\t\t...generateDebugEvent(\"GENERATE_TREE_EDIT_COMPLETED\", debugOptions.traceId),\n\t\t\teventFlowName: EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,\n\t\t\teventFlowStatus: \"COMPLETED\",\n\t\t\teventFlowTraceId: generateTreeEditEventFlowId,\n\t\t\tisLlmResponseValid: wrapper?.edit !== undefined,\n\t\t\tllmGeneratedEdit: wrapper?.edit as Record<string, unknown> | null,\n\t\t} satisfies GenerateTreeEditCompleted);\n\n\t\tif (wrapper === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (wrapper.edit === null) {\n\t\t\tif ((options.finalReviewStep ?? false) && !hasReviewed) {\n\t\t\t\tconst reviewResult = await reviewGoal();\n\t\t\t\tif (reviewResult === undefined) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\t// eslint-disable-next-line require-atomic-updates\n\t\t\t\thasReviewed = true;\n\t\t\t\tif (reviewResult.goalAccomplished === \"yes\") {\n\t\t\t\t\treturn undefined;\n\t\t\t\t} else {\n\t\t\t\t\t// eslint-disable-next-line require-atomic-updates\n\t\t\t\t\teditLog.length = 0;\n\t\t\t\t\treturn getNextEdit();\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\treturn { edit: wrapper.edit, eventFlowTraceId: generateTreeEditEventFlowId };\n\t\t}\n\t}\n\n\tasync function reviewGoal(): Promise<ReviewResult | undefined> {\n\t\tconst systemPrompt = getReviewSystemPrompt(\n\t\t\toptions.prompt.userAsk,\n\t\t\tidGenerator,\n\t\t\toptions.treeNode,\n\t\t\toriginalDecoratedJson ?? fail(\"Original decorated tree not provided.\"),\n\t\t\toptions.prompt.systemRoleContext,\n\t\t);\n\n\t\tconst schema = z.object({\n\t\t\tgoalAccomplished: z\n\t\t\t\t.enum([\"yes\", \"no\"])\n\t\t\t\t.describe('Whether the user\\'s goal was met in the \"after\" tree.'),\n\t\t});\n\n\t\tconst finalReviewEventFlowTraceId = uuidv4();\n\t\tdebugOptions?.eventLogHandler?.({\n\t\t\t...generateDebugEvent(\"FINAL_REVIEW_STARTED\", debugOptions.traceId),\n\t\t\teventFlowName: EventFlowDebugNames.FINAL_REVIEW,\n\t\t\teventFlowStatus: \"STARTED\",\n\t\t\teventFlowTraceId: finalReviewEventFlowTraceId,\n\t\t\tllmPrompt: systemPrompt,\n\t\t} satisfies FinalReviewStarted);\n\n\t\t// TODO: In the future, when using structured output isn't guarenteed, we will\n\t\t// need to add a custom type guard to ensure that output is in the right shape.\n\t\tconst output = await getStructuredOutputFromLlm<ReviewResult>(\n\t\t\tsystemPrompt,\n\t\t\toptions.openAI,\n\t\t\tschema,\n\t\t\tundefined,\n\t\t\ttokensUsed,\n\t\t\tdebugOptions && {\n\t\t\t\t...debugOptions,\n\t\t\t\ttriggeringEventFlowName: EventFlowDebugNames.FINAL_REVIEW,\n\t\t\t\teventFlowTraceId: finalReviewEventFlowTraceId,\n\t\t\t},\n\t\t);\n\n\t\tdebugOptions?.eventLogHandler?.({\n\t\t\t...generateDebugEvent(\"FINAL_REVIEW_COMPLETED\", debugOptions.traceId),\n\t\t\teventFlowName: EventFlowDebugNames.FINAL_REVIEW,\n\t\t\teventFlowStatus: \"COMPLETED\",\n\t\t\teventFlowTraceId: finalReviewEventFlowTraceId,\n\t\t\tisLlmResponseValid: output !== undefined,\n\t\t\tdidLlmAccomplishGoal: output?.goalAccomplished,\n\t\t} satisfies FinalReviewCompleted);\n\n\t\treturn output;\n\t}\n\n\tlet edit = await getNextEdit();\n\twhile (edit !== undefined) {\n\t\tyield edit;\n\t\tif (tokensUsed.inputTokens > (tokenLimits?.inputTokens ?? Number.POSITIVE_INFINITY)) {\n\t\t\tthrow new TokenLimitExceededError(\"Input token limit exceeded.\");\n\t\t}\n\t\tif (tokensUsed.outputTokens > (tokenLimits?.outputTokens ?? Number.POSITIVE_INFINITY)) {\n\t\t\tthrow new TokenLimitExceededError(\"Output token limit exceeded.\");\n\t\t}\n\t\tedit = await getNextEdit();\n\t}\n}\n\n/**\n * Calls the LLM to generate a structured output response based on the provided prompt.\n */\nasync function getStructuredOutputFromLlm<T>(\n\tprompt: string,\n\topenAi: OpenAiClientOptions,\n\tstructuredOutputSchema: Zod.ZodTypeAny,\n\tdescription?: string,\n\ttokensUsed?: TokenUsage,\n\tdebugOptions?: {\n\t\teventLogHandler: DebugEventLogHandler;\n\t\ttraceId: string;\n\t\ttriggeringEventFlowName: EventFlowDebugName;\n\t\teventFlowTraceId: string;\n\t},\n): Promise<T | undefined> {\n\tconst response_format = zodResponseFormat(structuredOutputSchema, \"SharedTreeAI\", {\n\t\tdescription,\n\t});\n\n\tconst body: ChatCompletionCreateParams = {\n\t\tmessages: [{ role: \"system\", content: prompt }],\n\t\tmodel: openAi.modelName ?? \"gpt-4o\",\n\t\tresponse_format,\n\t};\n\n\tconst result = await openAi.client.beta.chat.completions.parse(body);\n\n\tdebugOptions?.eventLogHandler?.({\n\t\t...generateDebugEvent(\"LLM_API_CALL\", debugOptions.traceId),\n\t\ttriggeringEventFlowName: debugOptions.triggeringEventFlowName,\n\t\teventFlowTraceId: debugOptions.eventFlowTraceId,\n\t\tmodelName: openAi.modelName ?? \"gpt-4o\",\n\t\trequestParams: body,\n\t\tresponse: { ...result },\n\t\t...(result.usage && {\n\t\t\ttokenUsage: {\n\t\t\t\tpromptTokens: result.usage.prompt_tokens,\n\t\t\t\tcompletionTokens: result.usage.completion_tokens,\n\t\t\t},\n\t\t}),\n\t} satisfies LlmApiCallDebugEvent);\n\n\tif (result.usage !== undefined && tokensUsed !== undefined) {\n\t\ttokensUsed.inputTokens += result.usage?.prompt_tokens;\n\t\ttokensUsed.outputTokens += result.usage?.completion_tokens;\n\t}\n\n\t// TODO: fix types so this isn't null and doesn't need a cast\n\t// The type should be derived from the zod schema\n\t// TODO: Determine why this value would be undefined.\n\treturn result.choices[0]?.message.parsed as T | undefined;\n}\n\n/**\n * Calls the LLM to generate a response based on the provided prompt.\n */\nasync function getStringFromLlm(\n\tprompt: string,\n\topenAi: OpenAiClientOptions,\n\ttokensUsed?: TokenUsage,\n\tdebugOptions?: {\n\t\teventLogHandler: DebugEventLogHandler;\n\t\ttraceId: string;\n\t\ttriggeringEventFlowName: EventFlowDebugName;\n\t\teventFlowTraceId: string;\n\t},\n): Promise<string | undefined> {\n\tconst body: ChatCompletionCreateParams = {\n\t\tmessages: [{ role: \"system\", content: prompt }],\n\t\tmodel: openAi.modelName ?? \"gpt-4o\",\n\t};\n\n\tconst result = await openAi.client.chat.completions.create(body);\n\n\tdebugOptions?.eventLogHandler?.({\n\t\t...generateDebugEvent(\"LLM_API_CALL\", debugOptions.traceId),\n\t\ttriggeringEventFlowName: debugOptions.triggeringEventFlowName,\n\t\teventFlowTraceId: debugOptions.eventFlowTraceId,\n\t\tmodelName: openAi.modelName ?? \"gpt-4o\",\n\t\trequestParams: body,\n\t\tresponse: { ...result },\n\t\t...(result.usage && {\n\t\t\ttokenUsage: {\n\t\t\t\tpromptTokens: result.usage.prompt_tokens,\n\t\t\t\tcompletionTokens: result.usage.completion_tokens,\n\t\t\t},\n\t\t}),\n\t} satisfies LlmApiCallDebugEvent);\n\n\tif (result.usage !== undefined && tokensUsed !== undefined) {\n\t\ttokensUsed.inputTokens += result.usage?.prompt_tokens;\n\t\ttokensUsed.outputTokens += result.usage?.completion_tokens;\n\t}\n\n\treturn result.choices[0]?.message.content ?? undefined;\n}\n\nclass TokenLimitExceededError extends Error {}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* @packageDocumentation
|
|
12
12
|
*/
|
|
13
13
|
export { type DifferenceCreate, type DifferenceChange, type DifferenceMove, type DifferenceRemove, type Difference, type ObjectPath, type Options, sharedTreeDiff, createMergableIdDiffSeries, createMergableDiffSeries, SharedTreeBranchManager, sharedTreeTraverse, } from "./implicit-strategy/index.js";
|
|
14
|
-
export {
|
|
14
|
+
export type { ApplyEditFailure, ApplyEditSuccess, CoreEventLoopCompleted, CoreEventLoopStarted, FinalReviewCompleted, FinalReviewStarted, GenerateTreeEditCompleted, GenerateTreeEditStarted, LlmApiCallDebugEvent, PlanningPromptCompleted, PlanningPromptStarted, LlmTreeEdit, EventFlowDebugName, EventFlowDebugNames, } from "./explicit-strategy/index.js";
|
|
15
|
+
export { type AiCollabOptions, type AiCollabSuccessResponse, type AiCollabErrorResponse, type TokenUsage, type TokenLimits, type OpenAiClientOptions, type DebugEvent, type DebugEventLogHandler, type EventFlowDebugEvent, } from "./aiCollabApi.js";
|
|
15
16
|
export { aiCollab } from "./aiCollab.js";
|
|
16
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;GAOG;AAEH,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,cAAc,EACd,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,kBAAkB,GAClB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,mBAAmB,GACxB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;GAOG;AAEH,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,cAAc,EACd,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,kBAAkB,GAClB,MAAM,8BAA8B,CAAC;AAEtC,YAAY,EACX,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,EACvB,qBAAqB,EACrB,WAAW,EACX,kBAAkB,EAClB,mBAAmB,GACnB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,UAAU,EACf,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,GACxB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;;;;;;GAOG;AAEH,yDAasC;AALrC,0GAAA,cAAc,OAAA;AACd,sHAAA,0BAA0B,OAAA;AAC1B,oHAAA,wBAAwB,OAAA;AACxB,mHAAA,uBAAuB,OAAA;AACvB,8GAAA,kBAAkB,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;;;;;;GAOG;AAEH,yDAasC;AALrC,0GAAA,cAAc,OAAA;AACd,sHAAA,0BAA0B,OAAA;AAC1B,oHAAA,wBAAwB,OAAA;AACxB,mHAAA,uBAAuB,OAAA;AACvB,8GAAA,kBAAkB,OAAA;AAgCnB,6CAAyC;AAAhC,uGAAA,QAAQ,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Experimental package for utilities that enable/simplify interaction with LLMs for apps based on SharedTree.\n *\n * See {@link https://github.com/microsoft/FluidFramework/tree/main/packages/framework/ai-collab#readme | README.md }\n * for an overview of the package.\n *\n * @packageDocumentation\n */\n\nexport {\n\ttype DifferenceCreate,\n\ttype DifferenceChange,\n\ttype DifferenceMove,\n\ttype DifferenceRemove,\n\ttype Difference,\n\ttype ObjectPath,\n\ttype Options,\n\tsharedTreeDiff,\n\tcreateMergableIdDiffSeries,\n\tcreateMergableDiffSeries,\n\tSharedTreeBranchManager,\n\tsharedTreeTraverse,\n} from \"./implicit-strategy/index.js\";\n\nexport type {\n\tApplyEditFailure,\n\tApplyEditSuccess,\n\tCoreEventLoopCompleted,\n\tCoreEventLoopStarted,\n\tFinalReviewCompleted,\n\tFinalReviewStarted,\n\tGenerateTreeEditCompleted,\n\tGenerateTreeEditStarted,\n\tLlmApiCallDebugEvent,\n\tPlanningPromptCompleted,\n\tPlanningPromptStarted,\n\tLlmTreeEdit,\n\tEventFlowDebugName,\n\tEventFlowDebugNames,\n} from \"./explicit-strategy/index.js\";\n\nexport {\n\ttype AiCollabOptions,\n\ttype AiCollabSuccessResponse,\n\ttype AiCollabErrorResponse,\n\ttype TokenUsage,\n\ttype TokenLimits,\n\ttype OpenAiClientOptions,\n\ttype DebugEvent,\n\ttype DebugEventLogHandler,\n\ttype EventFlowDebugEvent,\n} from \"./aiCollabApi.js\";\n\nexport { aiCollab } from \"./aiCollab.js\";\n"]}
|
package/lib/aiCollab.d.ts
CHANGED
package/lib/aiCollab.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiCollab.d.ts","sourceRoot":"","sources":["../src/aiCollab.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,qBAAqB,EACrB,eAAe,EACf,uBAAuB,EACvB,MAAM,kBAAkB,CAAC;AAG1B
|
|
1
|
+
{"version":3,"file":"aiCollab.d.ts","sourceRoot":"","sources":["../src/aiCollab.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,qBAAqB,EACrB,eAAe,EACf,uBAAuB,EACvB,MAAM,kBAAkB,CAAC;AAG1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAsB,QAAQ,CAC7B,OAAO,EAAE,eAAe,GACtB,OAAO,CAAC,uBAAuB,GAAG,qBAAqB,CAAC,CAa1D"}
|
package/lib/aiCollab.js
CHANGED
|
@@ -46,7 +46,6 @@ import { generateTreeEdits } from "./explicit-strategy/index.js";
|
|
|
46
46
|
* },
|
|
47
47
|
* planningStep: true,
|
|
48
48
|
* finalReviewStep: true,
|
|
49
|
-
* dumpDebugLog: true,
|
|
50
49
|
* });
|
|
51
50
|
* ```
|
|
52
51
|
*
|
|
@@ -68,9 +67,9 @@ export async function aiCollab(options) {
|
|
|
68
67
|
openAI: options.openAI,
|
|
69
68
|
prompt: options.prompt,
|
|
70
69
|
limiters: options.limiters,
|
|
71
|
-
dumpDebugLog: options.dumpDebugLog,
|
|
72
70
|
planningStep: options.planningStep,
|
|
73
71
|
finalReviewStep: options.finalReviewStep,
|
|
72
|
+
debugEventLogHandler: options.debugEventLogHandler,
|
|
74
73
|
});
|
|
75
74
|
return response;
|
|
76
75
|
}
|
package/lib/aiCollab.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aiCollab.js","sourceRoot":"","sources":["../src/aiCollab.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE
|
|
1
|
+
{"version":3,"file":"aiCollab.js","sourceRoot":"","sources":["../src/aiCollab.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC7B,OAAwB;IAExB,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC;QACxC,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,oBAAoB,EAAE,OAAO,CAAC,oBAAoB;KAClD,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AACjB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tAiCollabErrorResponse,\n\tAiCollabOptions,\n\tAiCollabSuccessResponse,\n} from \"./aiCollabApi.js\";\nimport { generateTreeEdits } from \"./explicit-strategy/index.js\";\n\n/**\n * Calls an LLM to modify the provided SharedTree in a series of real time edits based on the provided users prompt input.\n * @remarks This function is designed to be a controlled \"all-in-one\" function that handles the entire process of calling an LLM to collaborative edit a SharedTree.\n *\n * @example\n * ```typescript\n * import {\n * \tSchemaFactory,\n * \tTreeViewConfiguration,\n * \ttype TreeView\n * } from \"@fluidframework/tree\";\n *\n * const sf = new SchemaFactory(\"todo-app\");\n *\n * class TodoTask extends sf.object(\"TodoTask\", {\n * \ttitle: sf.string,\n * \tdescription: sf.string,\n * }) {}\n *\n * class TodoAppState extends sf.object(\"TodoAppState\", {\n * \ttasks: sf.array(TodoTask),\n * }) {}\n *\n * // Initialize your SharedTree\n * const treeView: TreeView = tree.viewWith(new TreeViewConfiguration({ schema: TodoAppState }));\n * treeView.initialize({ tasks: [] });\n *\n * // Collaborate with AI in realtime in just one function call.\n * const response = await aiCollab({\n * \t\topenAI: {\n * \t\t\tclient: new OpenAI({\n * \t\t\t\tapiKey: OPENAI_API_KEY,\n * \t\t\t}),\n * \t\t\tmodelName: \"gpt-4o\",\n * \t\t},\n * \t\ttreeNode: view.root,\n * \t\tprompt: {\n * \t\t\tsystemRoleContext:\n * \t\t\t\t\"You are an helpful assistant managing a todo list for a user.\",\n * \t\t\tuserAsk: \"Create a set of new todos to plan a vacation to Cancun.\",\n * \t\t},\n * \t\tplanningStep: true,\n * \t\tfinalReviewStep: true,\n * \t});\n * ```\n *\n * @remarks Known Limitiations:\n * - Root level array nodes are not supported\n * - Nested arrays are not supported\n * - Primitive nodes are not supported, e.g. 'string', 'number', 'boolean'\n * - Your application's Shared Tree schema must have no more than 4 levels of nesting\n * - Optional nodes are not supported in the Shared Tree schema\n * - Union types are not supported in the Shared Tree schema\n * - See README for more details.\n *\n * @alpha\n */\nexport async function aiCollab(\n\toptions: AiCollabOptions,\n): Promise<AiCollabSuccessResponse | AiCollabErrorResponse> {\n\tconst response = await generateTreeEdits({\n\t\ttreeNode: options.treeNode,\n\t\tvalidator: options.validator,\n\t\topenAI: options.openAI,\n\t\tprompt: options.prompt,\n\t\tlimiters: options.limiters,\n\t\tplanningStep: options.planningStep,\n\t\tfinalReviewStep: options.finalReviewStep,\n\t\tdebugEventLogHandler: options.debugEventLogHandler,\n\t});\n\n\treturn response;\n}\n"]}
|
package/lib/aiCollabApi.d.ts
CHANGED
|
@@ -4,6 +4,52 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { TreeNode } from "@fluidframework/tree";
|
|
6
6
|
import type OpenAI from "openai";
|
|
7
|
+
/**
|
|
8
|
+
* Core Debug event type for the ai-collab
|
|
9
|
+
* @alpha
|
|
10
|
+
*/
|
|
11
|
+
export interface DebugEvent {
|
|
12
|
+
/**
|
|
13
|
+
* The unique id of the debug event.
|
|
14
|
+
*/
|
|
15
|
+
id: string;
|
|
16
|
+
/**
|
|
17
|
+
* An id that will be shared across all debug events that originate from the same single execution of ai-collab.
|
|
18
|
+
* @remarks This is intended to be used to correlate all debug events that originate from the same execution
|
|
19
|
+
*/
|
|
20
|
+
traceId: string;
|
|
21
|
+
/**
|
|
22
|
+
* The name of the debug event.
|
|
23
|
+
*/
|
|
24
|
+
eventName: string;
|
|
25
|
+
/**
|
|
26
|
+
* The date and time at which the debug event was created.
|
|
27
|
+
*/
|
|
28
|
+
timestamp: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A Debug event that marks the start or end of a single core logic flow, such as generated tree edits, planning prompt, etc.
|
|
32
|
+
* @alpha
|
|
33
|
+
*/
|
|
34
|
+
export interface EventFlowDebugEvent extends DebugEvent {
|
|
35
|
+
/**
|
|
36
|
+
* The name of the particular event flow.
|
|
37
|
+
*/
|
|
38
|
+
eventFlowName: string;
|
|
39
|
+
/**
|
|
40
|
+
* The status of the particular event flow.
|
|
41
|
+
*/
|
|
42
|
+
eventFlowStatus: "STARTED" | "COMPLETED" | "IN_PROGRESS";
|
|
43
|
+
/**
|
|
44
|
+
* A unique id that will be shared across all debug events that are part of the same event flow.
|
|
45
|
+
*/
|
|
46
|
+
eventFlowTraceId: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A callback function that can be used to handle debug events that occur during the AI collaboration process.
|
|
50
|
+
* @alpha
|
|
51
|
+
*/
|
|
52
|
+
export type DebugEventLogHandler = <T extends DebugEvent>(event: T) => unknown;
|
|
7
53
|
/**
|
|
8
54
|
* OpenAI client options for the {@link AiCollabOptions} interface.
|
|
9
55
|
*
|
|
@@ -95,9 +141,9 @@ export interface AiCollabOptions {
|
|
|
95
141
|
*/
|
|
96
142
|
readonly validator?: (newContent: TreeNode) => void;
|
|
97
143
|
/**
|
|
98
|
-
*
|
|
144
|
+
* An optional handler for debug events that occur during the AI collaboration.
|
|
99
145
|
*/
|
|
100
|
-
readonly
|
|
146
|
+
readonly debugEventLogHandler?: DebugEventLogHandler;
|
|
101
147
|
}
|
|
102
148
|
/**
|
|
103
149
|
* A successful response from the AI collaboration.
|
|
@@ -133,8 +179,9 @@ export interface AiCollabErrorResponse {
|
|
|
133
179
|
* - 'tooManyErrors' indicates that the LLM made too many errors in a row
|
|
134
180
|
* - 'tooManyModelCalls' indicates that the LLM made too many model calls
|
|
135
181
|
* - 'aborted' indicates that the AI collaboration was aborted by the user or a limiter
|
|
182
|
+
* - 'unexpectedError' indicates that an unexpected error occured
|
|
136
183
|
*/
|
|
137
|
-
readonly errorMessage: "tokenLimitExceeded" | "tooManyErrors" | "tooManyModelCalls" | "aborted";
|
|
184
|
+
readonly errorMessage: "tokenLimitExceeded" | "tooManyErrors" | "tooManyModelCalls" | "aborted" | "unexpectedError";
|
|
138
185
|
/**
|
|
139
186
|
* {@inheritDoc TokenUsage}
|
|
140
187
|
*/
|