@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
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
+
import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
5
6
|
import { getSimpleSchema, Tree, } from "@fluidframework/tree/internal";
|
|
6
7
|
// eslint-disable-next-line import/no-internal-modules
|
|
7
8
|
import { zodResponseFormat } from "openai/helpers/zod";
|
|
9
|
+
import { v4 as uuidv4 } from "uuid";
|
|
8
10
|
import { z } from "zod";
|
|
9
11
|
import { applyAgentEdit } from "./agentEditReducer.js";
|
|
12
|
+
import { generateDebugEvent, EventFlowDebugNames, } from "./debugEvents.js";
|
|
10
13
|
import { IdGenerator } from "./idGenerator.js";
|
|
11
14
|
import { getEditingSystemPrompt, getPlanningSystemPrompt, getReviewSystemPrompt, toDecoratedJson, } from "./promptGeneration.js";
|
|
12
15
|
import { generateGenericEditTypes } from "./typeGeneration.js";
|
|
13
16
|
import { fail } from "./utils.js";
|
|
14
|
-
const DEBUG_LOG = [];
|
|
15
17
|
/**
|
|
16
18
|
* Prompts the provided LLM client to generate valid tree edits.
|
|
17
19
|
* Applies those edits to the provided tree branch before returning.
|
|
@@ -29,57 +31,92 @@ export async function generateTreeEdits(options) {
|
|
|
29
31
|
let sequentialErrorCount = 0;
|
|
30
32
|
const simpleSchema = getSimpleSchema(Tree.schema(options.treeNode));
|
|
31
33
|
const tokensUsed = { inputTokens: 0, outputTokens: 0 };
|
|
34
|
+
const debugLogTraceId = uuidv4();
|
|
35
|
+
const coreEventFlowTraceId = uuidv4();
|
|
36
|
+
options.debugEventLogHandler?.({
|
|
37
|
+
...generateDebugEvent("CORE_EVENT_LOOP_STARTED", debugLogTraceId),
|
|
38
|
+
eventFlowName: EventFlowDebugNames.CORE_EVENT_LOOP,
|
|
39
|
+
eventFlowStatus: "STARTED",
|
|
40
|
+
eventFlowTraceId: coreEventFlowTraceId,
|
|
41
|
+
});
|
|
32
42
|
try {
|
|
33
|
-
for await (const
|
|
43
|
+
for await (const generateEditResult of generateEdits(options, simpleSchema, idGenerator, editLog, options.limiters?.tokenLimits, tokensUsed, options.debugEventLogHandler && {
|
|
44
|
+
eventLogHandler: options.debugEventLogHandler,
|
|
45
|
+
traceId: debugLogTraceId,
|
|
46
|
+
})) {
|
|
34
47
|
try {
|
|
35
|
-
const result = applyAgentEdit(edit, idGenerator, simpleSchema.definitions, options.validator);
|
|
48
|
+
const result = applyAgentEdit(generateEditResult.edit, idGenerator, simpleSchema.definitions, options.validator);
|
|
36
49
|
const explanation = result.explanation;
|
|
37
50
|
editLog.push({ edit: { ...result, explanation } });
|
|
38
51
|
sequentialErrorCount = 0;
|
|
52
|
+
options.debugEventLogHandler?.({
|
|
53
|
+
...generateDebugEvent("APPLIED_EDIT_SUCCESS", debugLogTraceId),
|
|
54
|
+
eventFlowName: EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,
|
|
55
|
+
eventFlowStatus: "IN_PROGRESS",
|
|
56
|
+
eventFlowTraceId: generateEditResult.eventFlowTraceId,
|
|
57
|
+
edit: generateEditResult.edit,
|
|
58
|
+
});
|
|
39
59
|
}
|
|
40
60
|
catch (error) {
|
|
41
|
-
|
|
61
|
+
options.debugEventLogHandler?.({
|
|
62
|
+
...generateDebugEvent("APPLIED_EDIT_FAILURE", debugLogTraceId),
|
|
63
|
+
eventFlowName: EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,
|
|
64
|
+
eventFlowStatus: "IN_PROGRESS",
|
|
65
|
+
eventFlowTraceId: generateEditResult.eventFlowTraceId,
|
|
66
|
+
edit: generateEditResult.edit,
|
|
67
|
+
errorMessage: error?.message,
|
|
68
|
+
sequentialErrorCount,
|
|
69
|
+
});
|
|
70
|
+
if (error instanceof UsageError) {
|
|
42
71
|
sequentialErrorCount += 1;
|
|
43
|
-
editLog.push({ edit, error: error.message });
|
|
44
|
-
DEBUG_LOG?.push(`Error: ${error.message}`);
|
|
72
|
+
editLog.push({ edit: generateEditResult.edit, error: error.message });
|
|
45
73
|
}
|
|
46
74
|
else {
|
|
47
75
|
throw error;
|
|
48
76
|
}
|
|
49
77
|
}
|
|
50
|
-
|
|
78
|
+
let shouldExitEarly = false;
|
|
79
|
+
const completionResponse = {
|
|
80
|
+
status: editCount > 0 && sequentialErrorCount < editCount ? "partial-failure" : "failure",
|
|
81
|
+
errorMessage: "unexpectedError",
|
|
82
|
+
tokensUsed,
|
|
83
|
+
};
|
|
51
84
|
if (options.limiters?.abortController?.signal.aborted === true) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
errorMessage: "aborted",
|
|
55
|
-
tokensUsed,
|
|
56
|
-
};
|
|
85
|
+
completionResponse.errorMessage = "aborted";
|
|
86
|
+
shouldExitEarly = true;
|
|
57
87
|
}
|
|
58
|
-
if (sequentialErrorCount >
|
|
88
|
+
else if (sequentialErrorCount >
|
|
59
89
|
(options.limiters?.maxSequentialErrors ?? Number.POSITIVE_INFINITY)) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
90
|
+
completionResponse.errorMessage = "tooManyErrors";
|
|
91
|
+
shouldExitEarly = true;
|
|
92
|
+
}
|
|
93
|
+
else if (++editCount >= (options.limiters?.maxModelCalls ?? Number.POSITIVE_INFINITY)) {
|
|
94
|
+
completionResponse.errorMessage = "tooManyModelCalls";
|
|
95
|
+
shouldExitEarly = true;
|
|
65
96
|
}
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
97
|
+
if (shouldExitEarly) {
|
|
98
|
+
options.debugEventLogHandler?.({
|
|
99
|
+
...generateDebugEvent("CORE_EVENT_LOOP_COMPLETED", debugLogTraceId),
|
|
100
|
+
eventFlowName: EventFlowDebugNames.CORE_EVENT_LOOP,
|
|
101
|
+
eventFlowStatus: "COMPLETED",
|
|
102
|
+
status: "failure",
|
|
103
|
+
failureReason: completionResponse.errorMessage,
|
|
104
|
+
eventFlowTraceId: coreEventFlowTraceId,
|
|
105
|
+
});
|
|
106
|
+
return completionResponse;
|
|
72
107
|
}
|
|
73
108
|
}
|
|
74
109
|
}
|
|
75
110
|
catch (error) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
111
|
+
options.debugEventLogHandler?.({
|
|
112
|
+
...generateDebugEvent("CORE_EVENT_LOOP_COMPLETED", debugLogTraceId),
|
|
113
|
+
eventFlowName: EventFlowDebugNames.CORE_EVENT_LOOP,
|
|
114
|
+
eventFlowStatus: "COMPLETED",
|
|
115
|
+
status: "failure",
|
|
116
|
+
eventFlowTraceId: coreEventFlowTraceId,
|
|
117
|
+
failureReason: error instanceof TokenLimitExceededError ? "tokenLimitExceeded" : "unexpectedError",
|
|
118
|
+
errorMessage: error?.message,
|
|
119
|
+
});
|
|
83
120
|
if (error instanceof TokenLimitExceededError) {
|
|
84
121
|
return {
|
|
85
122
|
status: editCount > 0 && sequentialErrorCount < editCount ? "partial-failure" : "failure",
|
|
@@ -89,10 +126,13 @@ export async function generateTreeEdits(options) {
|
|
|
89
126
|
}
|
|
90
127
|
throw error;
|
|
91
128
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
129
|
+
options.debugEventLogHandler?.({
|
|
130
|
+
...generateDebugEvent("CORE_EVENT_LOOP_COMPLETED", debugLogTraceId),
|
|
131
|
+
eventFlowName: EventFlowDebugNames.CORE_EVENT_LOOP,
|
|
132
|
+
eventFlowStatus: "COMPLETED",
|
|
133
|
+
eventFlowTraceId: coreEventFlowTraceId,
|
|
134
|
+
status: "success",
|
|
135
|
+
});
|
|
96
136
|
return {
|
|
97
137
|
status: "success",
|
|
98
138
|
tokensUsed,
|
|
@@ -107,14 +147,31 @@ export async function generateTreeEdits(options) {
|
|
|
107
147
|
* Once the LLM believes it has completed the user's ask, it will no longer return an edit and as a result
|
|
108
148
|
* this generator will no longer yield a next value.
|
|
109
149
|
*/
|
|
110
|
-
async function* generateEdits(options, simpleSchema, idGenerator, editLog, tokenLimits, tokensUsed) {
|
|
150
|
+
async function* generateEdits(options, simpleSchema, idGenerator, editLog, tokenLimits, tokensUsed, debugOptions) {
|
|
111
151
|
const [types, rootTypeName] = generateGenericEditTypes(simpleSchema, true);
|
|
112
152
|
let plan;
|
|
113
153
|
if (options.planningStep !== undefined) {
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
154
|
+
const planningPrompt = getPlanningSystemPrompt(options.treeNode, options.prompt.userAsk, options.prompt.systemRoleContext);
|
|
155
|
+
const generatePlanningPromptEventFlowId = uuidv4();
|
|
156
|
+
debugOptions?.eventLogHandler?.({
|
|
157
|
+
...generateDebugEvent("GENERATE_PLANNING_PROMPT_STARTED", debugOptions.traceId),
|
|
158
|
+
eventFlowName: EventFlowDebugNames.GENERATE_PLANNING_PROMPT,
|
|
159
|
+
eventFlowTraceId: generatePlanningPromptEventFlowId,
|
|
160
|
+
eventFlowStatus: "STARTED",
|
|
161
|
+
});
|
|
162
|
+
plan = await getStringFromLlm(planningPrompt, options.openAI, tokensUsed, debugOptions && {
|
|
163
|
+
...debugOptions,
|
|
164
|
+
triggeringEventFlowName: EventFlowDebugNames.GENERATE_PLANNING_PROMPT,
|
|
165
|
+
eventFlowTraceId: generatePlanningPromptEventFlowId,
|
|
166
|
+
});
|
|
167
|
+
debugOptions?.eventLogHandler?.({
|
|
168
|
+
...generateDebugEvent("GENERATE_PLANNING_PROMPT_COMPLETED", debugOptions.traceId),
|
|
169
|
+
eventFlowName: EventFlowDebugNames.GENERATE_PLANNING_PROMPT,
|
|
170
|
+
eventFlowStatus: "COMPLETED",
|
|
171
|
+
eventFlowTraceId: generatePlanningPromptEventFlowId,
|
|
172
|
+
isLlmResponseValid: plan !== undefined,
|
|
173
|
+
llmGeneratedPlan: plan,
|
|
174
|
+
});
|
|
118
175
|
}
|
|
119
176
|
const originalDecoratedJson = (options.finalReviewStep ?? false)
|
|
120
177
|
? toDecoratedJson(idGenerator, options.treeNode)
|
|
@@ -123,21 +180,35 @@ async function* generateEdits(options, simpleSchema, idGenerator, editLog, token
|
|
|
123
180
|
let hasReviewed = (options.finalReviewStep ?? false) ? false : true;
|
|
124
181
|
async function getNextEdit() {
|
|
125
182
|
const systemPrompt = getEditingSystemPrompt(options.prompt.userAsk, idGenerator, options.treeNode, editLog, options.prompt.systemRoleContext, plan);
|
|
126
|
-
DEBUG_LOG?.push(systemPrompt);
|
|
127
183
|
const schema = types[rootTypeName] ?? fail("Root type not found.");
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
184
|
+
const generateTreeEditEventFlowId = uuidv4();
|
|
185
|
+
debugOptions?.eventLogHandler?.({
|
|
186
|
+
...generateDebugEvent("GENERATE_TREE_EDIT_STARTED", debugOptions.traceId),
|
|
187
|
+
eventFlowName: EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,
|
|
188
|
+
eventFlowStatus: "STARTED",
|
|
189
|
+
eventFlowTraceId: generateTreeEditEventFlowId,
|
|
190
|
+
llmPrompt: systemPrompt,
|
|
191
|
+
});
|
|
192
|
+
const wrapper = await getStructuredOutputFromLlm(systemPrompt, options.openAI, schema, "A JSON object that represents an edit to a JSON tree.", tokensUsed, debugOptions && {
|
|
193
|
+
...debugOptions,
|
|
194
|
+
triggeringEventFlowName: EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,
|
|
195
|
+
eventFlowTraceId: generateTreeEditEventFlowId,
|
|
196
|
+
});
|
|
197
|
+
debugOptions?.eventLogHandler?.({
|
|
198
|
+
...generateDebugEvent("GENERATE_TREE_EDIT_COMPLETED", debugOptions.traceId),
|
|
199
|
+
eventFlowName: EventFlowDebugNames.GENERATE_AND_APPLY_TREE_EDIT,
|
|
200
|
+
eventFlowStatus: "COMPLETED",
|
|
201
|
+
eventFlowTraceId: generateTreeEditEventFlowId,
|
|
202
|
+
isLlmResponseValid: wrapper?.edit !== undefined,
|
|
203
|
+
llmGeneratedEdit: wrapper?.edit,
|
|
204
|
+
});
|
|
131
205
|
if (wrapper === undefined) {
|
|
132
|
-
DEBUG_LOG?.push("Failed to get response");
|
|
133
206
|
return undefined;
|
|
134
207
|
}
|
|
135
208
|
if (wrapper.edit === null) {
|
|
136
|
-
DEBUG_LOG?.push("No more edits.");
|
|
137
209
|
if ((options.finalReviewStep ?? false) && !hasReviewed) {
|
|
138
210
|
const reviewResult = await reviewGoal();
|
|
139
211
|
if (reviewResult === undefined) {
|
|
140
|
-
DEBUG_LOG?.push("Failed to get review response");
|
|
141
212
|
return undefined;
|
|
142
213
|
}
|
|
143
214
|
// eslint-disable-next-line require-atomic-updates
|
|
@@ -153,18 +224,40 @@ async function* generateEdits(options, simpleSchema, idGenerator, editLog, token
|
|
|
153
224
|
}
|
|
154
225
|
}
|
|
155
226
|
else {
|
|
156
|
-
return wrapper.edit;
|
|
227
|
+
return { edit: wrapper.edit, eventFlowTraceId: generateTreeEditEventFlowId };
|
|
157
228
|
}
|
|
158
229
|
}
|
|
159
230
|
async function reviewGoal() {
|
|
160
231
|
const systemPrompt = getReviewSystemPrompt(options.prompt.userAsk, idGenerator, options.treeNode, originalDecoratedJson ?? fail("Original decorated tree not provided."), options.prompt.systemRoleContext);
|
|
161
|
-
DEBUG_LOG?.push(systemPrompt);
|
|
162
232
|
const schema = z.object({
|
|
163
233
|
goalAccomplished: z
|
|
164
234
|
.enum(["yes", "no"])
|
|
165
235
|
.describe('Whether the user\'s goal was met in the "after" tree.'),
|
|
166
236
|
});
|
|
167
|
-
|
|
237
|
+
const finalReviewEventFlowTraceId = uuidv4();
|
|
238
|
+
debugOptions?.eventLogHandler?.({
|
|
239
|
+
...generateDebugEvent("FINAL_REVIEW_STARTED", debugOptions.traceId),
|
|
240
|
+
eventFlowName: EventFlowDebugNames.FINAL_REVIEW,
|
|
241
|
+
eventFlowStatus: "STARTED",
|
|
242
|
+
eventFlowTraceId: finalReviewEventFlowTraceId,
|
|
243
|
+
llmPrompt: systemPrompt,
|
|
244
|
+
});
|
|
245
|
+
// TODO: In the future, when using structured output isn't guarenteed, we will
|
|
246
|
+
// need to add a custom type guard to ensure that output is in the right shape.
|
|
247
|
+
const output = await getStructuredOutputFromLlm(systemPrompt, options.openAI, schema, undefined, tokensUsed, debugOptions && {
|
|
248
|
+
...debugOptions,
|
|
249
|
+
triggeringEventFlowName: EventFlowDebugNames.FINAL_REVIEW,
|
|
250
|
+
eventFlowTraceId: finalReviewEventFlowTraceId,
|
|
251
|
+
});
|
|
252
|
+
debugOptions?.eventLogHandler?.({
|
|
253
|
+
...generateDebugEvent("FINAL_REVIEW_COMPLETED", debugOptions.traceId),
|
|
254
|
+
eventFlowName: EventFlowDebugNames.FINAL_REVIEW,
|
|
255
|
+
eventFlowStatus: "COMPLETED",
|
|
256
|
+
eventFlowTraceId: finalReviewEventFlowTraceId,
|
|
257
|
+
isLlmResponseValid: output !== undefined,
|
|
258
|
+
didLlmAccomplishGoal: output?.goalAccomplished,
|
|
259
|
+
});
|
|
260
|
+
return output;
|
|
168
261
|
}
|
|
169
262
|
let edit = await getNextEdit();
|
|
170
263
|
while (edit !== undefined) {
|
|
@@ -181,7 +274,7 @@ async function* generateEdits(options, simpleSchema, idGenerator, editLog, token
|
|
|
181
274
|
/**
|
|
182
275
|
* Calls the LLM to generate a structured output response based on the provided prompt.
|
|
183
276
|
*/
|
|
184
|
-
async function getStructuredOutputFromLlm(prompt, openAi, structuredOutputSchema, description, tokensUsed) {
|
|
277
|
+
async function getStructuredOutputFromLlm(prompt, openAi, structuredOutputSchema, description, tokensUsed, debugOptions) {
|
|
185
278
|
const response_format = zodResponseFormat(structuredOutputSchema, "SharedTreeAI", {
|
|
186
279
|
description,
|
|
187
280
|
});
|
|
@@ -191,23 +284,52 @@ async function getStructuredOutputFromLlm(prompt, openAi, structuredOutputSchema
|
|
|
191
284
|
response_format,
|
|
192
285
|
};
|
|
193
286
|
const result = await openAi.client.beta.chat.completions.parse(body);
|
|
287
|
+
debugOptions?.eventLogHandler?.({
|
|
288
|
+
...generateDebugEvent("LLM_API_CALL", debugOptions.traceId),
|
|
289
|
+
triggeringEventFlowName: debugOptions.triggeringEventFlowName,
|
|
290
|
+
eventFlowTraceId: debugOptions.eventFlowTraceId,
|
|
291
|
+
modelName: openAi.modelName ?? "gpt-4o",
|
|
292
|
+
requestParams: body,
|
|
293
|
+
response: { ...result },
|
|
294
|
+
...(result.usage && {
|
|
295
|
+
tokenUsage: {
|
|
296
|
+
promptTokens: result.usage.prompt_tokens,
|
|
297
|
+
completionTokens: result.usage.completion_tokens,
|
|
298
|
+
},
|
|
299
|
+
}),
|
|
300
|
+
});
|
|
194
301
|
if (result.usage !== undefined && tokensUsed !== undefined) {
|
|
195
302
|
tokensUsed.inputTokens += result.usage?.prompt_tokens;
|
|
196
303
|
tokensUsed.outputTokens += result.usage?.completion_tokens;
|
|
197
304
|
}
|
|
198
305
|
// TODO: fix types so this isn't null and doesn't need a cast
|
|
199
306
|
// The type should be derived from the zod schema
|
|
307
|
+
// TODO: Determine why this value would be undefined.
|
|
200
308
|
return result.choices[0]?.message.parsed;
|
|
201
309
|
}
|
|
202
310
|
/**
|
|
203
311
|
* Calls the LLM to generate a response based on the provided prompt.
|
|
204
312
|
*/
|
|
205
|
-
async function getStringFromLlm(prompt, openAi, tokensUsed) {
|
|
313
|
+
async function getStringFromLlm(prompt, openAi, tokensUsed, debugOptions) {
|
|
206
314
|
const body = {
|
|
207
315
|
messages: [{ role: "system", content: prompt }],
|
|
208
316
|
model: openAi.modelName ?? "gpt-4o",
|
|
209
317
|
};
|
|
210
318
|
const result = await openAi.client.chat.completions.create(body);
|
|
319
|
+
debugOptions?.eventLogHandler?.({
|
|
320
|
+
...generateDebugEvent("LLM_API_CALL", debugOptions.traceId),
|
|
321
|
+
triggeringEventFlowName: debugOptions.triggeringEventFlowName,
|
|
322
|
+
eventFlowTraceId: debugOptions.eventFlowTraceId,
|
|
323
|
+
modelName: openAi.modelName ?? "gpt-4o",
|
|
324
|
+
requestParams: body,
|
|
325
|
+
response: { ...result },
|
|
326
|
+
...(result.usage && {
|
|
327
|
+
tokenUsage: {
|
|
328
|
+
promptTokens: result.usage.prompt_tokens,
|
|
329
|
+
completionTokens: result.usage.completion_tokens,
|
|
330
|
+
},
|
|
331
|
+
}),
|
|
332
|
+
});
|
|
211
333
|
if (result.usage !== undefined && tokensUsed !== undefined) {
|
|
212
334
|
tokensUsed.inputTokens += result.usage?.prompt_tokens;
|
|
213
335
|
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":"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","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/lib/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/lib/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/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;GAOG;AAEH,OAAO,EAQN,cAAc,EACd,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,kBAAkB,GAClB,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;GAOG;AAEH,OAAO,EAQN,cAAc,EACd,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,kBAAkB,GAClB,MAAM,8BAA8B,CAAC;AA+BtC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC","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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/ai-collab",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.23.0",
|
|
4
4
|
"description": "Experimental package to simplify integrating AI into Fluid-based applications",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -69,28 +69,30 @@
|
|
|
69
69
|
"temp-directory": "nyc/.nyc_output"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@fluidframework/core-utils": "~2.
|
|
73
|
-
"@fluidframework/runtime-utils": "~2.
|
|
74
|
-
"@fluidframework/telemetry-utils": "~2.
|
|
75
|
-
"@fluidframework/tree": "~2.
|
|
72
|
+
"@fluidframework/core-utils": "~2.23.0",
|
|
73
|
+
"@fluidframework/runtime-utils": "~2.23.0",
|
|
74
|
+
"@fluidframework/telemetry-utils": "~2.23.0",
|
|
75
|
+
"@fluidframework/tree": "~2.23.0",
|
|
76
76
|
"openai": "^4.67.3",
|
|
77
77
|
"typechat": "^0.1.1",
|
|
78
|
+
"uuid": "^9.0.0",
|
|
78
79
|
"zod": "^3.23.8"
|
|
79
80
|
},
|
|
80
81
|
"devDependencies": {
|
|
81
82
|
"@arethetypeswrong/cli": "^0.17.1",
|
|
82
83
|
"@biomejs/biome": "~1.9.3",
|
|
83
|
-
"@fluid-internal/mocha-test-setup": "~2.
|
|
84
|
-
"@fluid-tools/build-cli": "^0.
|
|
84
|
+
"@fluid-internal/mocha-test-setup": "~2.23.0",
|
|
85
|
+
"@fluid-tools/build-cli": "^0.54.0",
|
|
85
86
|
"@fluidframework/build-common": "^2.0.3",
|
|
86
|
-
"@fluidframework/build-tools": "^0.
|
|
87
|
+
"@fluidframework/build-tools": "^0.54.0",
|
|
87
88
|
"@fluidframework/eslint-config-fluid": "^5.7.3",
|
|
88
|
-
"@fluidframework/id-compressor": "~2.
|
|
89
|
-
"@fluidframework/runtime-utils": "~2.
|
|
90
|
-
"@fluidframework/test-runtime-utils": "~2.
|
|
89
|
+
"@fluidframework/id-compressor": "~2.23.0",
|
|
90
|
+
"@fluidframework/runtime-utils": "~2.23.0",
|
|
91
|
+
"@fluidframework/test-runtime-utils": "~2.23.0",
|
|
91
92
|
"@microsoft/api-extractor": "7.47.8",
|
|
92
93
|
"@types/mocha": "^10.0.10",
|
|
93
94
|
"@types/node": "^18.19.0",
|
|
95
|
+
"@types/uuid": "^9.0.2",
|
|
94
96
|
"c8": "^8.0.1",
|
|
95
97
|
"concurrently": "^8.2.1",
|
|
96
98
|
"copyfiles": "^2.4.1",
|
package/src/aiCollab.ts
CHANGED
|
@@ -53,7 +53,6 @@ import { generateTreeEdits } from "./explicit-strategy/index.js";
|
|
|
53
53
|
* },
|
|
54
54
|
* planningStep: true,
|
|
55
55
|
* finalReviewStep: true,
|
|
56
|
-
* dumpDebugLog: true,
|
|
57
56
|
* });
|
|
58
57
|
* ```
|
|
59
58
|
*
|
|
@@ -77,9 +76,9 @@ export async function aiCollab(
|
|
|
77
76
|
openAI: options.openAI,
|
|
78
77
|
prompt: options.prompt,
|
|
79
78
|
limiters: options.limiters,
|
|
80
|
-
dumpDebugLog: options.dumpDebugLog,
|
|
81
79
|
planningStep: options.planningStep,
|
|
82
80
|
finalReviewStep: options.finalReviewStep,
|
|
81
|
+
debugEventLogHandler: options.debugEventLogHandler,
|
|
83
82
|
});
|
|
84
83
|
|
|
85
84
|
return response;
|