@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.
Files changed (47) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +70 -4
  3. package/api-report/ai-collab.alpha.api.md +170 -2
  4. package/dist/aiCollab.d.ts +0 -1
  5. package/dist/aiCollab.d.ts.map +1 -1
  6. package/dist/aiCollab.js +1 -2
  7. package/dist/aiCollab.js.map +1 -1
  8. package/dist/aiCollabApi.d.ts +50 -3
  9. package/dist/aiCollabApi.d.ts.map +1 -1
  10. package/dist/aiCollabApi.js.map +1 -1
  11. package/dist/alpha.d.ts +17 -0
  12. package/dist/explicit-strategy/debugEvents.d.ts +248 -0
  13. package/dist/explicit-strategy/debugEvents.d.ts.map +1 -0
  14. package/dist/explicit-strategy/debugEvents.js +36 -0
  15. package/dist/explicit-strategy/debugEvents.js.map +1 -0
  16. package/dist/explicit-strategy/index.d.ts +4 -4
  17. package/dist/explicit-strategy/index.d.ts.map +1 -1
  18. package/dist/explicit-strategy/index.js +176 -54
  19. package/dist/explicit-strategy/index.js.map +1 -1
  20. package/dist/index.d.ts +2 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/lib/aiCollab.d.ts +0 -1
  24. package/lib/aiCollab.d.ts.map +1 -1
  25. package/lib/aiCollab.js +1 -2
  26. package/lib/aiCollab.js.map +1 -1
  27. package/lib/aiCollabApi.d.ts +50 -3
  28. package/lib/aiCollabApi.d.ts.map +1 -1
  29. package/lib/aiCollabApi.js.map +1 -1
  30. package/lib/alpha.d.ts +17 -0
  31. package/lib/explicit-strategy/debugEvents.d.ts +248 -0
  32. package/lib/explicit-strategy/debugEvents.d.ts.map +1 -0
  33. package/lib/explicit-strategy/debugEvents.js +32 -0
  34. package/lib/explicit-strategy/debugEvents.js.map +1 -0
  35. package/lib/explicit-strategy/index.d.ts +4 -4
  36. package/lib/explicit-strategy/index.d.ts.map +1 -1
  37. package/lib/explicit-strategy/index.js +174 -52
  38. package/lib/explicit-strategy/index.js.map +1 -1
  39. package/lib/index.d.ts +2 -1
  40. package/lib/index.d.ts.map +1 -1
  41. package/lib/index.js.map +1 -1
  42. package/package.json +13 -11
  43. package/src/aiCollab.ts +1 -2
  44. package/src/aiCollabApi.ts +54 -3
  45. package/src/explicit-strategy/debugEvents.ts +297 -0
  46. package/src/explicit-strategy/index.ts +269 -59
  47. 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/tree/internal");
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, internal_1.getSimpleSchema)(internal_1.Tree.schema(options.treeNode));
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 edit of generateEdits(options, simpleSchema, idGenerator, editLog, options.limiters?.tokenLimits, tokensUsed)) {
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
- if (error instanceof Error) {
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
- const responseStatus = editCount > 0 && sequentialErrorCount < editCount ? "partial-failure" : "failure";
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
- return {
56
- status: responseStatus,
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
- return {
64
- status: responseStatus,
65
- errorMessage: "tooManyErrors",
66
- tokensUsed,
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 (++editCount >= (options.limiters?.maxModelCalls ?? Number.POSITIVE_INFINITY)) {
70
- return {
71
- status: responseStatus,
72
- errorMessage: "tooManyModelCalls",
73
- tokensUsed,
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
- if (error instanceof Error) {
80
- DEBUG_LOG?.push(`Error: ${error.message}`);
81
- }
82
- if (options.dumpDebugLog ?? false) {
83
- console.log(DEBUG_LOG.join("\n\n"));
84
- DEBUG_LOG.length = 0;
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
- if (options.dumpDebugLog ?? false) {
96
- console.log(DEBUG_LOG.join("\n\n"));
97
- DEBUG_LOG.length = 0;
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 planningPromt = (0, promptGeneration_js_1.getPlanningSystemPrompt)(options.treeNode, options.prompt.userAsk, options.prompt.systemRoleContext);
119
- DEBUG_LOG?.push(planningPromt);
120
- plan = await getStringFromLlm(planningPromt, options.openAI, tokensUsed);
121
- DEBUG_LOG?.push(`AI Generated the following plan: ${planningPromt}`);
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 wrapper = await getStructuredOutputFromLlm(systemPrompt, options.openAI, schema, "A JSON object that represents an edit to a JSON tree.", tokensUsed);
133
- // eslint-disable-next-line unicorn/no-null
134
- DEBUG_LOG?.push(JSON.stringify(wrapper, null, 2));
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
- return getStructuredOutputFromLlm(systemPrompt, options.openAI, schema);
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":"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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/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 { type AiCollabOptions, type AiCollabSuccessResponse, type AiCollabErrorResponse, type TokenUsage, type TokenLimits, type OpenAiClientOptions, } from "./aiCollabApi.js";
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
@@ -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;AAYnB,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 {\n\ttype AiCollabOptions,\n\ttype AiCollabSuccessResponse,\n\ttype AiCollabErrorResponse,\n\ttype TokenUsage,\n\ttype TokenLimits,\n\ttype OpenAiClientOptions,\n} from \"./aiCollabApi.js\";\n\nexport { aiCollab } from \"./aiCollab.js\";\n"]}
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
@@ -46,7 +46,6 @@ import type { AiCollabErrorResponse, AiCollabOptions, AiCollabSuccessResponse }
46
46
  * },
47
47
  * planningStep: true,
48
48
  * finalReviewStep: true,
49
- * dumpDebugLog: true,
50
49
  * });
51
50
  * ```
52
51
  *
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,wBAAsB,QAAQ,CAC7B,OAAO,EAAE,eAAe,GACtB,OAAO,CAAC,uBAAuB,GAAG,qBAAqB,CAAC,CAa1D"}
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
  }
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;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,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,eAAe,EAAE,OAAO,CAAC,eAAe;KACxC,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\tdumpDebugLog: 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\tdumpDebugLog: options.dumpDebugLog,\n\t\tplanningStep: options.planningStep,\n\t\tfinalReviewStep: options.finalReviewStep,\n\t});\n\n\treturn response;\n}\n"]}
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"]}
@@ -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
- * When enabled, the library will console.log information useful for debugging the AI collaboration.
144
+ * An optional handler for debug events that occur during the AI collaboration.
99
145
  */
100
- readonly dumpDebugLog?: boolean;
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
  */