@bike4mind/cli 0.2.2 → 0.2.3-feat-questmaster-gpt5-function-calling.17055

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.
File without changes
@@ -6,7 +6,7 @@ import {
6
6
  getSettingsByNames,
7
7
  obfuscateApiKey,
8
8
  secureParameters
9
- } from "./chunk-NZADYDFG.js";
9
+ } from "./chunk-NH74I6GX.js";
10
10
  import {
11
11
  ApiKeyType,
12
12
  MementoTier,
File without changes
File without changes
File without changes
@@ -7,7 +7,7 @@ import {
7
7
  getSettingsMap,
8
8
  getSettingsValue,
9
9
  secureParameters
10
- } from "./chunk-NZADYDFG.js";
10
+ } from "./chunk-NH74I6GX.js";
11
11
  import {
12
12
  KnowledgeType,
13
13
  SupportedFabFileMimeTypes
@@ -4112,6 +4112,12 @@ var OpenAIBackend = class {
4112
4112
  }
4113
4113
  if (options.tools?.length) {
4114
4114
  parameters.tools = this.formatTools(options.tools);
4115
+ if (options.tool_choice) {
4116
+ parameters.tool_choice = options.tool_choice;
4117
+ }
4118
+ if (options.parallel_tool_calls !== void 0) {
4119
+ parameters.parallel_tool_calls = options.parallel_tool_calls;
4120
+ }
4115
4121
  }
4116
4122
  const response = await this._api.chat.completions.create(parameters, {
4117
4123
  signal: options.abortSignal
@@ -7978,6 +7984,147 @@ function extractQuestMasterData(reply, options = {}) {
7978
7984
  return questMasterData;
7979
7985
  }
7980
7986
 
7987
+ // ../../b4m-core/packages/utils/dist/src/questMasterToolSchema.js
7988
+ var GPT5_MODELS_WITH_TOOL_SUPPORT = [
7989
+ ChatModels.GPT5,
7990
+ ChatModels.GPT5_MINI,
7991
+ ChatModels.GPT5_NANO,
7992
+ ChatModels.GPT5_1,
7993
+ ChatModels.GPT5_2
7994
+ ];
7995
+ function isGPT5ModelWithToolSupport(model) {
7996
+ return GPT5_MODELS_WITH_TOOL_SUPPORT.includes(model);
7997
+ }
7998
+ var createQuestPlanToolSchema = {
7999
+ name: "create_quest_plan",
8000
+ description: `Break down a user request into a structured quest plan with actionable tasks.
8001
+
8002
+ GUIDELINES:
8003
+ - Analyze the user's request and create 3-7 main quests
8004
+ - Each quest must have 2-5 specific, actionable subquests
8005
+ - Quest titles should be clear and action-oriented (e.g., "Set up database schema" not "Step 1")
8006
+ - Provide detailed descriptions for each quest
8007
+ - Assess complexity accurately: Easy (< 1 hour), Medium (1-4 hours), Hard (> 4 hours)
8008
+ - Generate 2-5 relevant tags categorizing the work (e.g., "web-development", "database", "api")
8009
+
8010
+ ALWAYS call this function to respond. Do NOT respond with plain text.`,
8011
+ parameters: {
8012
+ type: "object",
8013
+ properties: {
8014
+ goal: {
8015
+ type: "string",
8016
+ description: "The overall objective the user wants to achieve"
8017
+ },
8018
+ tags: {
8019
+ type: "array",
8020
+ items: { type: "string" },
8021
+ description: 'Categories for this quest (e.g., "web-development", "api", "database")'
8022
+ },
8023
+ quests: {
8024
+ type: "array",
8025
+ description: "The main quests (3-7) that break down the goal",
8026
+ items: {
8027
+ type: "object",
8028
+ properties: {
8029
+ id: {
8030
+ type: "string",
8031
+ description: 'Unique identifier (e.g., "quest-1", "setup-database")'
8032
+ },
8033
+ title: {
8034
+ type: "string",
8035
+ description: 'Clear, action-oriented title (e.g., "Configure authentication middleware")'
8036
+ },
8037
+ description: {
8038
+ type: "string",
8039
+ description: "Detailed explanation of what needs to be done and why"
8040
+ },
8041
+ complexity: {
8042
+ type: "string",
8043
+ enum: ["Easy", "Medium", "Hard"],
8044
+ description: "Difficulty assessment based on effort required"
8045
+ },
8046
+ subQuests: {
8047
+ type: "array",
8048
+ description: "Concrete subtasks (2-5) within this quest",
8049
+ items: {
8050
+ type: "object",
8051
+ properties: {
8052
+ id: {
8053
+ type: "string",
8054
+ description: "Unique identifier for the subquest"
8055
+ },
8056
+ title: {
8057
+ type: "string",
8058
+ description: "Specific, actionable subtask title"
8059
+ }
8060
+ },
8061
+ required: ["id", "title"]
8062
+ }
8063
+ }
8064
+ },
8065
+ required: ["id", "title", "description", "complexity", "subQuests"]
8066
+ }
8067
+ }
8068
+ },
8069
+ required: ["goal", "quests"]
8070
+ }
8071
+ };
8072
+ function parseQuestPlanFunctionCall(args) {
8073
+ let parsed;
8074
+ try {
8075
+ parsed = JSON.parse(args);
8076
+ } catch (e) {
8077
+ throw new Error(`Failed to parse function call arguments as JSON: ${e}`);
8078
+ }
8079
+ if (!parsed || typeof parsed !== "object") {
8080
+ throw new Error("Function call arguments must be an object");
8081
+ }
8082
+ const result = parsed;
8083
+ if (!result.goal || typeof result.goal !== "string") {
8084
+ throw new Error("Function call missing required field: goal");
8085
+ }
8086
+ if (!Array.isArray(result.quests)) {
8087
+ throw new Error("Function call missing required field: quests (must be an array)");
8088
+ }
8089
+ if (result.quests.length === 0) {
8090
+ throw new Error("Function call returned empty quests array");
8091
+ }
8092
+ for (let i = 0; i < result.quests.length; i++) {
8093
+ const quest = result.quests[i];
8094
+ if (!quest.id || typeof quest.id !== "string") {
8095
+ throw new Error(`Quest ${i} missing required field: id`);
8096
+ }
8097
+ if (!quest.title || typeof quest.title !== "string") {
8098
+ throw new Error(`Quest ${i} missing required field: title`);
8099
+ }
8100
+ if (!quest.description || typeof quest.description !== "string") {
8101
+ throw new Error(`Quest ${i} missing required field: description`);
8102
+ }
8103
+ if (!quest.complexity || !["Easy", "Medium", "Hard"].includes(quest.complexity)) {
8104
+ throw new Error(`Quest ${i} has invalid complexity: ${quest.complexity} (must be Easy, Medium, or Hard)`);
8105
+ }
8106
+ if (!Array.isArray(quest.subQuests)) {
8107
+ throw new Error(`Quest "${quest.id}" missing required field: subQuests (must be an array)`);
8108
+ }
8109
+ if (quest.subQuests.length === 0) {
8110
+ throw new Error(`Quest "${quest.id}" has no subQuests (minimum 2 required)`);
8111
+ }
8112
+ for (let j = 0; j < quest.subQuests.length; j++) {
8113
+ const subQuest = quest.subQuests[j];
8114
+ if (!subQuest.id || typeof subQuest.id !== "string") {
8115
+ throw new Error(`Quest "${quest.id}" subQuest ${j} missing required field: id`);
8116
+ }
8117
+ if (!subQuest.title || typeof subQuest.title !== "string") {
8118
+ throw new Error(`Quest "${quest.id}" subQuest ${j} missing required field: title`);
8119
+ }
8120
+ }
8121
+ }
8122
+ if (result.tags !== void 0 && !Array.isArray(result.tags)) {
8123
+ throw new Error("Function call field tags must be an array if provided");
8124
+ }
8125
+ return result;
8126
+ }
8127
+
7981
8128
  // ../../b4m-core/packages/utils/dist/src/questMaster.js
7982
8129
  var sanitizeId = (id) => {
7983
8130
  return id.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9_.-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
@@ -8008,10 +8155,9 @@ var QuestMaster = class {
8008
8155
  }
8009
8156
  return "Easy";
8010
8157
  }
8011
- async processQuestPlan(questPlanText) {
8158
+ async processQuestPlan(input) {
8012
8159
  try {
8013
8160
  await this.onStatusUpdate(this.quest, "Processing quest plan...");
8014
- this.logger.log("Processing quest plan:", questPlanText);
8015
8161
  const defaultResponse = {
8016
8162
  type: "narrative",
8017
8163
  meta: {
@@ -8028,135 +8174,161 @@ var QuestMaster = class {
8028
8174
  }
8029
8175
  ]
8030
8176
  };
8031
- if (!questPlanText || typeof questPlanText !== "string") {
8032
- this.logger.warn("Invalid questPlanText received:", questPlanText);
8033
- if (this.quest) {
8034
- this.quest.questMasterReply = JSON.stringify(defaultResponse);
8035
- await this.db.quests.update({
8036
- id: this.quest.id,
8037
- questMasterReply: this.quest.questMasterReply,
8038
- reply: null,
8039
- replies: [],
8040
- status: "done",
8041
- type: "message"
8042
- });
8043
- }
8044
- return;
8045
- }
8046
8177
  if (!this.quest) {
8047
8178
  throw new Error("No quest context available");
8048
8179
  }
8049
- const extracted = extractQuestMasterData(questPlanText, { logger: this.logger });
8050
- const metaStartTag = "<!--QuestMasterMeta";
8051
- const metaEndTag = "-->";
8052
- const metaStartIndex = questPlanText.indexOf(metaStartTag);
8053
- let goal = "Quest Plan";
8054
- let tags = [];
8055
8180
  let questResponse;
8056
- if (metaStartIndex !== -1) {
8057
- const metaEndIndex = questPlanText.indexOf(metaEndTag, metaStartIndex);
8058
- if (metaEndIndex !== -1) {
8059
- const metaContent = questPlanText.slice(metaStartIndex + metaStartTag.length, metaEndIndex).trim();
8060
- try {
8061
- const jsonStartIndex = metaContent.indexOf("{");
8062
- if (jsonStartIndex !== -1) {
8063
- const metaData = JSON.parse(metaContent.slice(jsonStartIndex));
8064
- goal = metaData.goal || goal;
8065
- tags = Array.isArray(metaData.tags) ? metaData.tags : [];
8066
- }
8067
- } catch (err) {
8068
- this.logger.error("Error parsing meta data:", err);
8069
- }
8070
- }
8071
- }
8072
- if (extracted.length > 0) {
8073
- this.logger.log("Successfully extracted QuestMaster data:", extracted);
8074
- await this.onStatusUpdate(this.quest, "Extracted QuestMaster data");
8075
- const validQuests = extracted.filter((quest) => quest !== null && typeof quest === "object" && quest.id && quest.title && quest.title !== "Step 1" && // Explicitly filter out generic Step 1
8076
- quest.description && quest.description !== "No description available");
8077
- if (validQuests.length === 0) {
8078
- throw new Error("No valid quests found after filtering");
8079
- }
8181
+ if (typeof input === "object") {
8182
+ this.logger.log("Processing quest plan from function calling result");
8080
8183
  questResponse = {
8081
8184
  type: "quest_plan",
8082
8185
  meta: {
8083
- goal,
8084
- totalSteps: validQuests.length,
8085
- tags
8186
+ goal: input.goal,
8187
+ totalSteps: input.quests.length,
8188
+ tags: input.tags
8086
8189
  },
8087
- quests: validQuests.map((quest) => ({
8190
+ quests: input.quests.map((quest) => ({
8088
8191
  id: quest.id,
8089
- // No fallback - we filtered for valid IDs
8090
8192
  title: quest.title,
8091
- // No fallback - we filtered for valid titles
8092
8193
  description: quest.description,
8093
- // No fallback - we filtered for valid descriptions
8094
- complexity: quest.complexity || "Medium",
8194
+ complexity: quest.complexity,
8095
8195
  status: "not_started",
8096
- subQuests: Array.isArray(quest.subQuests) ? quest.subQuests.filter((sub) => sub && sub.id && sub.title && !sub.title.startsWith("Subtask")).map((sub) => ({
8196
+ subQuests: quest.subQuests.map((sub) => ({
8097
8197
  id: sub.id,
8098
8198
  title: sub.title,
8099
8199
  status: "not_started"
8100
- })) : []
8200
+ }))
8101
8201
  }))
8102
8202
  };
8103
- if (questResponse.quests.some((quest) => quest.subQuests.length === 0)) {
8104
- throw new Error("Some quests have no valid subquests after filtering");
8105
- }
8106
8203
  } else {
8107
- try {
8108
- const questPlan = JSON.parse(questPlanText);
8109
- if (questPlan && questPlan.questChain && Array.isArray(questPlan.questChain)) {
8110
- const validQuestChain = questPlan.questChain.filter((item) => item && item.quest && item.quest !== "Step 1" && item.details && item.details !== "No description available");
8111
- if (validQuestChain.length === 0) {
8112
- throw new Error("No valid quests found in quest chain");
8204
+ const questPlanText = input;
8205
+ this.logger.log("Processing quest plan:", questPlanText);
8206
+ if (!questPlanText || typeof questPlanText !== "string") {
8207
+ this.logger.warn("Invalid questPlanText received:", questPlanText);
8208
+ if (this.quest) {
8209
+ this.quest.questMasterReply = JSON.stringify(defaultResponse);
8210
+ await this.db.quests.update({
8211
+ id: this.quest.id,
8212
+ questMasterReply: this.quest.questMasterReply,
8213
+ reply: null,
8214
+ replies: [],
8215
+ status: "done",
8216
+ type: "message"
8217
+ });
8218
+ }
8219
+ return;
8220
+ }
8221
+ const extracted = extractQuestMasterData(questPlanText, { logger: this.logger });
8222
+ const metaStartTag = "<!--QuestMasterMeta";
8223
+ const metaEndTag = "-->";
8224
+ const metaStartIndex = questPlanText.indexOf(metaStartTag);
8225
+ let goal = "Quest Plan";
8226
+ let tags = [];
8227
+ if (metaStartIndex !== -1) {
8228
+ const metaEndIndex = questPlanText.indexOf(metaEndTag, metaStartIndex);
8229
+ if (metaEndIndex !== -1) {
8230
+ const metaContent = questPlanText.slice(metaStartIndex + metaStartTag.length, metaEndIndex).trim();
8231
+ try {
8232
+ const jsonStartIndex = metaContent.indexOf("{");
8233
+ if (jsonStartIndex !== -1) {
8234
+ const metaData = JSON.parse(metaContent.slice(jsonStartIndex));
8235
+ goal = metaData.goal || goal;
8236
+ tags = Array.isArray(metaData.tags) ? metaData.tags : [];
8237
+ }
8238
+ } catch (err) {
8239
+ this.logger.error("Error parsing meta data:", err);
8113
8240
  }
8114
- questResponse = {
8115
- type: "quest_plan",
8116
- meta: {
8117
- goal: questPlan.abstractObjective || "Process Request",
8118
- totalSteps: validQuestChain.length
8119
- },
8120
- quests: validQuestChain.map((item, index) => ({
8121
- id: `quest-${index + 1}`,
8122
- title: item.quest,
8123
- description: item.details,
8124
- complexity: this.determineComplexity(item.details),
8125
- status: "Not Started",
8126
- subQuests: []
8127
- // This will trigger a retry since we require subquests
8128
- }))
8129
- };
8130
- } else {
8131
- if (!questPlanText.trim() || questPlanText.trim() === "Step 1") {
8132
- throw new Error("Empty or invalid response received");
8241
+ }
8242
+ }
8243
+ if (extracted.length > 0) {
8244
+ this.logger.log("Successfully extracted QuestMaster data:", extracted);
8245
+ await this.onStatusUpdate(this.quest, "Extracted QuestMaster data");
8246
+ const validQuests = extracted.filter((quest) => quest !== null && typeof quest === "object" && quest.id && quest.title && quest.title !== "Step 1" && // Explicitly filter out generic Step 1
8247
+ quest.description && quest.description !== "No description available");
8248
+ if (validQuests.length === 0) {
8249
+ throw new Error("No valid quests found after filtering");
8250
+ }
8251
+ questResponse = {
8252
+ type: "quest_plan",
8253
+ meta: {
8254
+ goal,
8255
+ totalSteps: validQuests.length,
8256
+ tags
8257
+ },
8258
+ quests: validQuests.map((quest) => ({
8259
+ id: quest.id,
8260
+ // No fallback - we filtered for valid IDs
8261
+ title: quest.title,
8262
+ // No fallback - we filtered for valid titles
8263
+ description: quest.description,
8264
+ // No fallback - we filtered for valid descriptions
8265
+ complexity: quest.complexity || "Medium",
8266
+ status: "not_started",
8267
+ subQuests: Array.isArray(quest.subQuests) ? quest.subQuests.filter((sub) => sub && sub.id && sub.title && !sub.title.startsWith("Subtask")).map((sub) => ({
8268
+ id: sub.id,
8269
+ title: sub.title,
8270
+ status: "not_started"
8271
+ })) : []
8272
+ }))
8273
+ };
8274
+ if (questResponse.quests.some((quest) => quest.subQuests.length === 0)) {
8275
+ throw new Error("Some quests have no valid subquests after filtering");
8276
+ }
8277
+ } else {
8278
+ try {
8279
+ const questPlan = JSON.parse(questPlanText);
8280
+ if (questPlan && questPlan.questChain && Array.isArray(questPlan.questChain)) {
8281
+ const validQuestChain = questPlan.questChain.filter((item) => item && item.quest && item.quest !== "Step 1" && item.details && item.details !== "No description available");
8282
+ if (validQuestChain.length === 0) {
8283
+ throw new Error("No valid quests found in quest chain");
8284
+ }
8285
+ questResponse = {
8286
+ type: "quest_plan",
8287
+ meta: {
8288
+ goal: questPlan.abstractObjective || "Process Request",
8289
+ totalSteps: validQuestChain.length
8290
+ },
8291
+ quests: validQuestChain.map((item, index) => ({
8292
+ id: `quest-${index + 1}`,
8293
+ title: item.quest,
8294
+ description: item.details,
8295
+ complexity: this.determineComplexity(item.details),
8296
+ status: "Not Started",
8297
+ subQuests: []
8298
+ // This will trigger a retry since we require subquests
8299
+ }))
8300
+ };
8301
+ } else {
8302
+ if (!questPlanText.trim() || questPlanText.trim() === "Step 1") {
8303
+ throw new Error("Empty or invalid response received");
8304
+ }
8305
+ questResponse = {
8306
+ type: "narrative",
8307
+ meta: {
8308
+ goal: "Direct Response",
8309
+ totalSteps: 1
8310
+ },
8311
+ quests: [
8312
+ {
8313
+ id: "narrative-1",
8314
+ title: "Process Response",
8315
+ description: questPlanText.trim(),
8316
+ complexity: "Medium",
8317
+ subQuests: [
8318
+ {
8319
+ id: "narrative-1-1",
8320
+ title: "Review Response",
8321
+ status: "not_started"
8322
+ }
8323
+ ]
8324
+ }
8325
+ ]
8326
+ };
8133
8327
  }
8134
- questResponse = {
8135
- type: "narrative",
8136
- meta: {
8137
- goal: "Direct Response",
8138
- totalSteps: 1
8139
- },
8140
- quests: [
8141
- {
8142
- id: "narrative-1",
8143
- title: "Process Response",
8144
- description: questPlanText.trim(),
8145
- complexity: "Medium",
8146
- subQuests: [
8147
- {
8148
- id: "narrative-1-1",
8149
- title: "Review Response",
8150
- status: "not_started"
8151
- }
8152
- ]
8153
- }
8154
- ]
8155
- };
8328
+ } catch (parseError) {
8329
+ this.logger.error("Error parsing quest plan JSON:", parseError);
8330
+ questResponse = defaultResponse;
8156
8331
  }
8157
- } catch (parseError) {
8158
- this.logger.error("Error parsing quest plan JSON:", parseError);
8159
- questResponse = defaultResponse;
8160
8332
  }
8161
8333
  }
8162
8334
  if (!this.validateQuestResponse(questResponse)) {
@@ -8356,9 +8528,102 @@ var QuestMaster = class {
8356
8528
  }
8357
8529
  -->`;
8358
8530
  }
8531
+ /**
8532
+ * Create a quest plan using GPT-5's function calling feature.
8533
+ * This method is used when the model is a GPT-5 variant that supports tools
8534
+ * but doesn't reliably follow HTML comment formatting.
8535
+ *
8536
+ * @param model - The GPT-5 model to use
8537
+ * @param prompt - The user's request to break down into quests
8538
+ * @returns The parsed quest plan result
8539
+ */
8540
+ async createQuestPlanWithFunctionCalling(model, prompt, retryCount = 0) {
8541
+ const MAX_RETRIES = 2;
8542
+ const messages = [
8543
+ {
8544
+ role: "system",
8545
+ content: `You are the QuestMaster, an AI agent that breaks down complex tasks into manageable quests.
8546
+
8547
+ When given a user request, you MUST call the create_quest_plan function to structure your response.
8548
+ Do NOT respond with plain text - ALWAYS use the function call.
8549
+
8550
+ Guidelines:
8551
+ - Break down complex tasks into 3-7 main quests
8552
+ - Each quest needs 2-5 specific, actionable subquests
8553
+ - Make titles clear and action-oriented (e.g., "Set up database schema" not "Step 1")
8554
+ - Provide detailed descriptions explaining what needs to be done
8555
+ - Assess complexity accurately: Easy (< 1 hour), Medium (1-4 hours), Hard (> 4 hours)
8556
+ - Generate 2-5 relevant tags categorizing the work`
8557
+ },
8558
+ { role: "user", content: prompt }
8559
+ ];
8560
+ const toolDef = {
8561
+ toolFn: async (params) => JSON.stringify(params),
8562
+ // Not executed, just captured
8563
+ toolSchema: createQuestPlanToolSchema
8564
+ };
8565
+ const options = {
8566
+ temperature: retryCount > 0 ? 0.7 : 0.9,
8567
+ // Lower temperature on retries
8568
+ n: 1,
8569
+ stream: false,
8570
+ tools: [toolDef],
8571
+ executeTools: false,
8572
+ // Don't execute, just capture the function call
8573
+ tool_choice: { type: "function", function: { name: "create_quest_plan" } },
8574
+ // Force function call
8575
+ parallel_tool_calls: false
8576
+ // Required for structured outputs
8577
+ };
8578
+ let functionResult = null;
8579
+ let lastError = null;
8580
+ try {
8581
+ await this.llm.complete(model, messages, options, async (text, completionInfo) => {
8582
+ if (completionInfo?.toolsUsed?.length) {
8583
+ const toolCall = completionInfo.toolsUsed[0];
8584
+ if (toolCall.name === "create_quest_plan" && toolCall.arguments) {
8585
+ this.logger.log("GPT-5 function call received, parsing arguments...");
8586
+ functionResult = parseQuestPlanFunctionCall(toolCall.arguments);
8587
+ }
8588
+ }
8589
+ });
8590
+ } catch (error) {
8591
+ lastError = error instanceof Error ? error : new Error(String(error));
8592
+ this.logger.error("Error in GPT-5 function calling:", lastError);
8593
+ }
8594
+ if (!functionResult) {
8595
+ if (retryCount < MAX_RETRIES) {
8596
+ this.logger.warn(`GPT-5 did not return function call, retrying (attempt ${retryCount + 1}/${MAX_RETRIES})...`);
8597
+ return this.createQuestPlanWithFunctionCalling(model, prompt, retryCount + 1);
8598
+ }
8599
+ throw lastError || new Error("GPT-5 did not call create_quest_plan function after retries");
8600
+ }
8601
+ const result = functionResult;
8602
+ const questsWithoutSubquests = result.quests.filter((q) => !q.subQuests || q.subQuests.length === 0);
8603
+ if (questsWithoutSubquests.length > 0 && retryCount < MAX_RETRIES) {
8604
+ this.logger.warn(`Some quests missing subquests: ${questsWithoutSubquests.map((q) => q.id).join(", ")}, retrying...`);
8605
+ return this.createQuestPlanWithFunctionCalling(model, prompt, retryCount + 1);
8606
+ }
8607
+ this.logger.log("Successfully received GPT-5 function call result:", {
8608
+ goal: result.goal,
8609
+ questCount: result.quests.length,
8610
+ tags: result.tags
8611
+ });
8612
+ return result;
8613
+ }
8359
8614
  async createQuestPlan(model, prompt) {
8360
8615
  try {
8361
8616
  await this.onStatusUpdate(this.quest, "Creating quest plan...");
8617
+ if (isGPT5ModelWithToolSupport(model)) {
8618
+ this.logger.log(`Using function calling approach for GPT-5 model: ${model}`);
8619
+ try {
8620
+ const result = await this.createQuestPlanWithFunctionCalling(model, prompt);
8621
+ await this.processQuestPlan(result);
8622
+ return;
8623
+ } catch (functionCallError) {
8624
+ this.logger.error("Function calling failed, falling back to HTML approach:", functionCallError);
8625
+ }
8626
+ }
8362
8627
  const messages = [
8363
8628
  {
8364
8629
  role: "system",
@@ -10452,6 +10717,9 @@ export {
10452
10717
  sendToConnection,
10453
10718
  ClientMessageSender,
10454
10719
  OpenaiModerationsService,
10720
+ isGPT5ModelWithToolSupport,
10721
+ createQuestPlanToolSchema,
10722
+ parseQuestPlanFunctionCall,
10455
10723
  QuestMaster,
10456
10724
  OpenAIImageService,
10457
10725
  TestImageService,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BadRequestError,
4
4
  secureParameters
5
- } from "./chunk-NZADYDFG.js";
5
+ } from "./chunk-NH74I6GX.js";
6
6
  import {
7
7
  GenericCreditDeductTransaction,
8
8
  ImageEditUsageTransaction,
File without changes
File without changes
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  createFabFile,
4
4
  createFabFileSchema
5
- } from "./chunk-5N4PG5EH.js";
6
- import "./chunk-NZADYDFG.js";
5
+ } from "./chunk-KDBSH6HC.js";
6
+ import "./chunk-NH74I6GX.js";
7
7
  import "./chunk-AMDXHL6S.js";
8
8
  import "./chunk-WR6YZRQV.js";
9
9
  import "./chunk-PDX44BCA.js";
File without changes
package/dist/index.js CHANGED
@@ -4,9 +4,9 @@ import {
4
4
  getEffectiveApiKey,
5
5
  getOpenWeatherKey,
6
6
  getSerperKey
7
- } from "./chunk-GZTILMGE.js";
8
- import "./chunk-Y4HMTEDH.js";
9
- import "./chunk-5N4PG5EH.js";
7
+ } from "./chunk-44WCHZA2.js";
8
+ import "./chunk-O2622ACK.js";
9
+ import "./chunk-KDBSH6HC.js";
10
10
  import {
11
11
  BFLImageService,
12
12
  BaseStorage,
@@ -15,7 +15,7 @@ import {
15
15
  OpenAIBackend,
16
16
  OpenAIImageService,
17
17
  XAIImageService
18
- } from "./chunk-NZADYDFG.js";
18
+ } from "./chunk-NH74I6GX.js";
19
19
  import {
20
20
  Logger
21
21
  } from "./chunk-AMDXHL6S.js";
@@ -9178,7 +9178,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
9178
9178
  // package.json
9179
9179
  var package_default = {
9180
9180
  name: "@bike4mind/cli",
9181
- version: "0.2.2",
9181
+ version: "0.2.3-feat-questmaster-gpt5-function-calling.17055+efa3267ae",
9182
9182
  type: "module",
9183
9183
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
9184
9184
  license: "UNLICENSED",
@@ -9279,11 +9279,11 @@ var package_default = {
9279
9279
  zustand: "^4.5.4"
9280
9280
  },
9281
9281
  devDependencies: {
9282
- "@bike4mind/agents": "workspace:*",
9283
- "@bike4mind/common": "workspace:*",
9284
- "@bike4mind/mcp": "workspace:*",
9285
- "@bike4mind/services": "workspace:*",
9286
- "@bike4mind/utils": "workspace:*",
9282
+ "@bike4mind/agents": "0.1.0",
9283
+ "@bike4mind/common": "2.37.1-feat-questmaster-gpt5-function-calling.17055+efa3267ae",
9284
+ "@bike4mind/mcp": "1.19.5-feat-questmaster-gpt5-function-calling.17055+efa3267ae",
9285
+ "@bike4mind/services": "2.31.1-feat-questmaster-gpt5-function-calling.17055+efa3267ae",
9286
+ "@bike4mind/utils": "2.0.4-feat-questmaster-gpt5-function-calling.17055+efa3267ae",
9287
9287
  "@types/diff": "^5.0.9",
9288
9288
  "@types/jsonwebtoken": "^9.0.4",
9289
9289
  "@types/node": "^22.9.0",
@@ -9294,7 +9294,8 @@ var package_default = {
9294
9294
  tsx: "^4.21.0",
9295
9295
  typescript: "^5.9.3",
9296
9296
  vitest: "^3.2.4"
9297
- }
9297
+ },
9298
+ gitHead: "efa3267ae1a98e505e89bb3b7e40caf68a8a1347"
9298
9299
  };
9299
9300
 
9300
9301
  // src/config/constants.ts
File without changes
File without changes
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  findMostSimilarMemento,
4
4
  getRelevantMementos
5
- } from "./chunk-GZTILMGE.js";
6
- import "./chunk-NZADYDFG.js";
5
+ } from "./chunk-44WCHZA2.js";
6
+ import "./chunk-NH74I6GX.js";
7
7
  import "./chunk-AMDXHL6S.js";
8
8
  import "./chunk-WR6YZRQV.js";
9
9
  import "./chunk-PDX44BCA.js";
File without changes
File without changes
@@ -65,6 +65,7 @@ import {
65
65
  cleanMermaidSyntax,
66
66
  computeCosineSimilarity,
67
67
  convertCodeBlocksToArtifacts,
68
+ createQuestPlanToolSchema,
68
69
  createTokenizer,
69
70
  decodeBase64DataUrl,
70
71
  detectURLs,
@@ -97,6 +98,7 @@ import {
97
98
  includeImagePromptSystemMessage,
98
99
  initializeConfig,
99
100
  invalidateSettingsCache,
101
+ isGPT5ModelWithToolSupport,
100
102
  isMermaidSyntax,
101
103
  isModelAccessible,
102
104
  isPlainText,
@@ -105,6 +107,7 @@ import {
105
107
  isZodError,
106
108
  obfuscateApiKey,
107
109
  parseArtifacts,
110
+ parseQuestPlanFunctionCall,
108
111
  processFabFilesServer,
109
112
  processUrlsFromPrompt,
110
113
  secureParameters,
@@ -117,7 +120,7 @@ import {
117
120
  validateMermaidSyntax,
118
121
  warmUpSettingsCache,
119
122
  withRetry
120
- } from "./chunk-NZADYDFG.js";
123
+ } from "./chunk-NH74I6GX.js";
121
124
  import {
122
125
  Logger,
123
126
  NotificationDeduplicator,
@@ -196,6 +199,7 @@ export {
196
199
  cleanMermaidSyntax,
197
200
  computeCosineSimilarity,
198
201
  convertCodeBlocksToArtifacts,
202
+ createQuestPlanToolSchema,
199
203
  createTokenizer,
200
204
  decodeBase64DataUrl,
201
205
  detectURLs,
@@ -228,6 +232,7 @@ export {
228
232
  includeImagePromptSystemMessage,
229
233
  initializeConfig,
230
234
  invalidateSettingsCache,
235
+ isGPT5ModelWithToolSupport,
231
236
  isMermaidSyntax,
232
237
  isModelAccessible,
233
238
  isPlainText,
@@ -238,6 +243,7 @@ export {
238
243
  notifyEventLogsToSlack,
239
244
  obfuscateApiKey,
240
245
  parseArtifacts,
246
+ parseQuestPlanFunctionCall,
241
247
  postLowCreditsNotificationToSlack,
242
248
  postMessageToSlack,
243
249
  processFabFilesServer,
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  SubtractCreditsSchema,
4
4
  subtractCredits
5
- } from "./chunk-Y4HMTEDH.js";
6
- import "./chunk-NZADYDFG.js";
5
+ } from "./chunk-O2622ACK.js";
6
+ import "./chunk-NH74I6GX.js";
7
7
  import "./chunk-AMDXHL6S.js";
8
8
  import "./chunk-WR6YZRQV.js";
9
9
  import "./chunk-PDX44BCA.js";
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bike4mind/cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.3-feat-questmaster-gpt5-function-calling.17055+efa3267ae",
4
4
  "type": "module",
5
5
  "description": "Interactive CLI tool for Bike4Mind with ReAct agents",
6
6
  "license": "UNLICENSED",
@@ -30,6 +30,15 @@
30
30
  "dist",
31
31
  "bin"
32
32
  ],
33
+ "scripts": {
34
+ "dev": "tsx src/index.tsx",
35
+ "build": "tsup",
36
+ "typecheck": "tsc --noEmit",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest",
39
+ "start": "node dist/index.js",
40
+ "prepublishOnly": "pnpm build"
41
+ },
33
42
  "dependencies": {
34
43
  "@anthropic-ai/sdk": "^0.22.0",
35
44
  "@aws-sdk/client-apigatewaymanagementapi": "3.654.0",
@@ -92,6 +101,11 @@
92
101
  "zustand": "^4.5.4"
93
102
  },
94
103
  "devDependencies": {
104
+ "@bike4mind/agents": "0.1.0",
105
+ "@bike4mind/common": "2.37.1-feat-questmaster-gpt5-function-calling.17055+efa3267ae",
106
+ "@bike4mind/mcp": "1.19.5-feat-questmaster-gpt5-function-calling.17055+efa3267ae",
107
+ "@bike4mind/services": "2.31.1-feat-questmaster-gpt5-function-calling.17055+efa3267ae",
108
+ "@bike4mind/utils": "2.0.4-feat-questmaster-gpt5-function-calling.17055+efa3267ae",
95
109
  "@types/diff": "^5.0.9",
96
110
  "@types/jsonwebtoken": "^9.0.4",
97
111
  "@types/node": "^22.9.0",
@@ -101,19 +115,7 @@
101
115
  "tsup": "^8.5.1",
102
116
  "tsx": "^4.21.0",
103
117
  "typescript": "^5.9.3",
104
- "vitest": "^3.2.4",
105
- "@bike4mind/common": "2.37.0",
106
- "@bike4mind/agents": "0.1.0",
107
- "@bike4mind/mcp": "1.19.4",
108
- "@bike4mind/services": "2.31.0",
109
- "@bike4mind/utils": "2.0.3"
118
+ "vitest": "^3.2.4"
110
119
  },
111
- "scripts": {
112
- "dev": "tsx src/index.tsx",
113
- "build": "tsup",
114
- "typecheck": "tsc --noEmit",
115
- "test": "vitest run",
116
- "test:watch": "vitest",
117
- "start": "node dist/index.js"
118
- }
119
- }
120
+ "gitHead": "efa3267ae1a98e505e89bb3b7e40caf68a8a1347"
121
+ }