@bike4mind/cli 0.2.3-feat-questmaster-gpt5-function-calling.17057 → 0.2.3-feat-cli-interactive-config-editor.17058
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-6AJODFPC.js → chunk-5N4PG5EH.js} +1 -1
- package/dist/{chunk-WNBKV4FX.js → chunk-GZTILMGE.js} +1 -1
- package/dist/{chunk-LYNNVNEC.js → chunk-NZADYDFG.js} +128 -463
- package/dist/{chunk-LEG2UM5Q.js → chunk-Y4HMTEDH.js} +1 -1
- package/dist/{create-LOAAI36O.js → create-ZTK4723N.js} +2 -2
- package/dist/index.js +283 -69
- package/dist/{mementoService-XGFAWC5F.js → mementoService-5XQYECNM.js} +2 -2
- package/dist/{src-32Z2VZMC.js → src-DOO3QAO2.js} +1 -7
- package/dist/{subtractCredits-VMGWNJS7.js → subtractCredits-3QOJA6XF.js} +2 -2
- package/package.json +6 -6
|
@@ -4112,12 +4112,6 @@ 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
|
-
}
|
|
4121
4115
|
}
|
|
4122
4116
|
const response = await this._api.chat.completions.create(parameters, {
|
|
4123
4117
|
signal: options.abortSignal
|
|
@@ -7984,200 +7978,9 @@ function extractQuestMasterData(reply, options = {}) {
|
|
|
7984
7978
|
return questMasterData;
|
|
7985
7979
|
}
|
|
7986
7980
|
|
|
7987
|
-
// ../../b4m-core/packages/utils/dist/src/questMasterToolSchema.js
|
|
7988
|
-
var MAX_GOAL_LENGTH = 500;
|
|
7989
|
-
var MAX_TITLE_LENGTH = 200;
|
|
7990
|
-
var MAX_DESCRIPTION_LENGTH = 2e3;
|
|
7991
|
-
var MAX_TAG_LENGTH = 50;
|
|
7992
|
-
var MAX_QUESTS = 20;
|
|
7993
|
-
var MAX_SUBQUESTS_PER_QUEST = 20;
|
|
7994
|
-
var MAX_TAGS = 10;
|
|
7995
|
-
var GPT5_MODELS_WITH_TOOL_SUPPORT = [
|
|
7996
|
-
ChatModels.GPT5,
|
|
7997
|
-
ChatModels.GPT5_MINI,
|
|
7998
|
-
ChatModels.GPT5_NANO,
|
|
7999
|
-
ChatModels.GPT5_1,
|
|
8000
|
-
ChatModels.GPT5_2
|
|
8001
|
-
];
|
|
8002
|
-
function isGPT5ModelWithToolSupport(model) {
|
|
8003
|
-
return GPT5_MODELS_WITH_TOOL_SUPPORT.includes(model);
|
|
8004
|
-
}
|
|
8005
|
-
var createQuestPlanToolSchema = {
|
|
8006
|
-
name: "create_quest_plan",
|
|
8007
|
-
description: `Break down a user request into a structured quest plan with actionable tasks.
|
|
8008
|
-
|
|
8009
|
-
GUIDELINES:
|
|
8010
|
-
- Analyze the user's request and create 3-7 main quests
|
|
8011
|
-
- Each quest must have 2-5 specific, actionable subquests
|
|
8012
|
-
- Quest titles should be clear and action-oriented (e.g., "Set up database schema" not "Step 1")
|
|
8013
|
-
- Provide detailed descriptions for each quest
|
|
8014
|
-
- Assess complexity accurately: Easy (< 1 hour), Medium (1-4 hours), Hard (> 4 hours)
|
|
8015
|
-
- Generate 2-5 relevant tags categorizing the work (e.g., "web-development", "database", "api")
|
|
8016
|
-
|
|
8017
|
-
ALWAYS call this function to respond. Do NOT respond with plain text.`,
|
|
8018
|
-
parameters: {
|
|
8019
|
-
type: "object",
|
|
8020
|
-
properties: {
|
|
8021
|
-
goal: {
|
|
8022
|
-
type: "string",
|
|
8023
|
-
description: "The overall objective the user wants to achieve"
|
|
8024
|
-
},
|
|
8025
|
-
tags: {
|
|
8026
|
-
type: "array",
|
|
8027
|
-
items: { type: "string" },
|
|
8028
|
-
description: 'Categories for this quest (e.g., "web-development", "api", "database")'
|
|
8029
|
-
},
|
|
8030
|
-
quests: {
|
|
8031
|
-
type: "array",
|
|
8032
|
-
description: "The main quests (3-7) that break down the goal",
|
|
8033
|
-
items: {
|
|
8034
|
-
type: "object",
|
|
8035
|
-
properties: {
|
|
8036
|
-
id: {
|
|
8037
|
-
type: "string",
|
|
8038
|
-
description: 'Unique identifier (e.g., "quest-1", "setup-database")'
|
|
8039
|
-
},
|
|
8040
|
-
title: {
|
|
8041
|
-
type: "string",
|
|
8042
|
-
description: 'Clear, action-oriented title (e.g., "Configure authentication middleware")'
|
|
8043
|
-
},
|
|
8044
|
-
description: {
|
|
8045
|
-
type: "string",
|
|
8046
|
-
description: "Detailed explanation of what needs to be done and why"
|
|
8047
|
-
},
|
|
8048
|
-
complexity: {
|
|
8049
|
-
type: "string",
|
|
8050
|
-
enum: ["Easy", "Medium", "Hard"],
|
|
8051
|
-
description: "Difficulty assessment based on effort required"
|
|
8052
|
-
},
|
|
8053
|
-
subQuests: {
|
|
8054
|
-
type: "array",
|
|
8055
|
-
description: "Concrete subtasks (2-5) within this quest",
|
|
8056
|
-
items: {
|
|
8057
|
-
type: "object",
|
|
8058
|
-
properties: {
|
|
8059
|
-
id: {
|
|
8060
|
-
type: "string",
|
|
8061
|
-
description: "Unique identifier for the subquest"
|
|
8062
|
-
},
|
|
8063
|
-
title: {
|
|
8064
|
-
type: "string",
|
|
8065
|
-
description: "Specific, actionable subtask title"
|
|
8066
|
-
}
|
|
8067
|
-
},
|
|
8068
|
-
required: ["id", "title"]
|
|
8069
|
-
}
|
|
8070
|
-
}
|
|
8071
|
-
},
|
|
8072
|
-
required: ["id", "title", "description", "complexity", "subQuests"]
|
|
8073
|
-
}
|
|
8074
|
-
}
|
|
8075
|
-
},
|
|
8076
|
-
required: ["goal", "quests"]
|
|
8077
|
-
}
|
|
8078
|
-
};
|
|
8079
|
-
function parseQuestPlanFunctionCall(args) {
|
|
8080
|
-
if (!args || typeof args !== "string" || args.trim() === "") {
|
|
8081
|
-
throw new Error("Function call arguments are empty or invalid");
|
|
8082
|
-
}
|
|
8083
|
-
let parsed;
|
|
8084
|
-
try {
|
|
8085
|
-
parsed = JSON.parse(args);
|
|
8086
|
-
} catch (e) {
|
|
8087
|
-
throw new Error(`Failed to parse function call arguments as JSON: ${e}`);
|
|
8088
|
-
}
|
|
8089
|
-
if (!parsed || typeof parsed !== "object") {
|
|
8090
|
-
throw new Error("Function call arguments must be an object");
|
|
8091
|
-
}
|
|
8092
|
-
const result = parsed;
|
|
8093
|
-
if (!result.goal || typeof result.goal !== "string" || result.goal.trim() === "") {
|
|
8094
|
-
throw new Error("Function call missing required field: goal (must be non-empty string)");
|
|
8095
|
-
}
|
|
8096
|
-
if (result.goal.length > MAX_GOAL_LENGTH) {
|
|
8097
|
-
throw new Error(`Goal exceeds maximum length of ${MAX_GOAL_LENGTH} characters`);
|
|
8098
|
-
}
|
|
8099
|
-
if (!Array.isArray(result.quests)) {
|
|
8100
|
-
throw new Error("Function call missing required field: quests (must be an array)");
|
|
8101
|
-
}
|
|
8102
|
-
if (result.quests.length === 0) {
|
|
8103
|
-
throw new Error("Function call returned empty quests array");
|
|
8104
|
-
}
|
|
8105
|
-
if (result.quests.length > MAX_QUESTS) {
|
|
8106
|
-
throw new Error(`Too many quests: ${result.quests.length} (max ${MAX_QUESTS})`);
|
|
8107
|
-
}
|
|
8108
|
-
for (let i = 0; i < result.quests.length; i++) {
|
|
8109
|
-
const quest = result.quests[i];
|
|
8110
|
-
if (!quest || typeof quest !== "object") {
|
|
8111
|
-
throw new Error(`Quest ${i} is not a valid object`);
|
|
8112
|
-
}
|
|
8113
|
-
const questObj = quest;
|
|
8114
|
-
if (!questObj.id || typeof questObj.id !== "string" || questObj.id.trim() === "") {
|
|
8115
|
-
throw new Error(`Quest ${i} missing required field: id (must be non-empty string)`);
|
|
8116
|
-
}
|
|
8117
|
-
if (!questObj.title || typeof questObj.title !== "string" || questObj.title.trim() === "") {
|
|
8118
|
-
throw new Error(`Quest ${i} missing required field: title (must be non-empty string)`);
|
|
8119
|
-
}
|
|
8120
|
-
if (questObj.title.length > MAX_TITLE_LENGTH) {
|
|
8121
|
-
throw new Error(`Quest ${i} title exceeds maximum length of ${MAX_TITLE_LENGTH} characters`);
|
|
8122
|
-
}
|
|
8123
|
-
if (!questObj.description || typeof questObj.description !== "string" || questObj.description.trim() === "") {
|
|
8124
|
-
throw new Error(`Quest ${i} missing required field: description (must be non-empty string)`);
|
|
8125
|
-
}
|
|
8126
|
-
if (questObj.description.length > MAX_DESCRIPTION_LENGTH) {
|
|
8127
|
-
throw new Error(`Quest ${i} description exceeds maximum length of ${MAX_DESCRIPTION_LENGTH} characters`);
|
|
8128
|
-
}
|
|
8129
|
-
if (!questObj.complexity || !["Easy", "Medium", "Hard"].includes(questObj.complexity)) {
|
|
8130
|
-
throw new Error(`Quest ${i} has invalid complexity: ${questObj.complexity} (must be Easy, Medium, or Hard)`);
|
|
8131
|
-
}
|
|
8132
|
-
if (!Array.isArray(questObj.subQuests)) {
|
|
8133
|
-
throw new Error(`Quest "${questObj.id}" missing required field: subQuests (must be an array)`);
|
|
8134
|
-
}
|
|
8135
|
-
if (questObj.subQuests.length === 0) {
|
|
8136
|
-
throw new Error(`Quest "${questObj.id}" has no subQuests (minimum 2 required)`);
|
|
8137
|
-
}
|
|
8138
|
-
if (questObj.subQuests.length > MAX_SUBQUESTS_PER_QUEST) {
|
|
8139
|
-
throw new Error(`Quest "${questObj.id}" has too many subQuests: ${questObj.subQuests.length} (max ${MAX_SUBQUESTS_PER_QUEST})`);
|
|
8140
|
-
}
|
|
8141
|
-
for (let j = 0; j < questObj.subQuests.length; j++) {
|
|
8142
|
-
const subQuest = questObj.subQuests[j];
|
|
8143
|
-
if (!subQuest || typeof subQuest !== "object") {
|
|
8144
|
-
throw new Error(`Quest "${questObj.id}" subQuest ${j} is not a valid object`);
|
|
8145
|
-
}
|
|
8146
|
-
const subQuestObj = subQuest;
|
|
8147
|
-
if (!subQuestObj.id || typeof subQuestObj.id !== "string" || subQuestObj.id.trim() === "") {
|
|
8148
|
-
throw new Error(`Quest "${questObj.id}" subQuest ${j} missing required field: id (must be non-empty string)`);
|
|
8149
|
-
}
|
|
8150
|
-
if (!subQuestObj.title || typeof subQuestObj.title !== "string" || subQuestObj.title.trim() === "") {
|
|
8151
|
-
throw new Error(`Quest "${questObj.id}" subQuest ${j} missing required field: title (must be non-empty string)`);
|
|
8152
|
-
}
|
|
8153
|
-
if (subQuestObj.title.length > MAX_TITLE_LENGTH) {
|
|
8154
|
-
throw new Error(`Quest "${questObj.id}" subQuest ${j} title exceeds maximum length of ${MAX_TITLE_LENGTH} characters`);
|
|
8155
|
-
}
|
|
8156
|
-
}
|
|
8157
|
-
}
|
|
8158
|
-
if (result.tags !== void 0) {
|
|
8159
|
-
if (!Array.isArray(result.tags)) {
|
|
8160
|
-
throw new Error("Function call field tags must be an array if provided");
|
|
8161
|
-
}
|
|
8162
|
-
if (result.tags.length > MAX_TAGS) {
|
|
8163
|
-
throw new Error(`Too many tags: ${result.tags.length} (max ${MAX_TAGS})`);
|
|
8164
|
-
}
|
|
8165
|
-
for (let i = 0; i < result.tags.length; i++) {
|
|
8166
|
-
if (typeof result.tags[i] !== "string") {
|
|
8167
|
-
throw new Error(`Function call field tags[${i}] must be a string`);
|
|
8168
|
-
}
|
|
8169
|
-
if (result.tags[i].length > MAX_TAG_LENGTH) {
|
|
8170
|
-
throw new Error(`Tag ${i} exceeds maximum length of ${MAX_TAG_LENGTH} characters`);
|
|
8171
|
-
}
|
|
8172
|
-
}
|
|
8173
|
-
}
|
|
8174
|
-
return result;
|
|
8175
|
-
}
|
|
8176
|
-
|
|
8177
7981
|
// ../../b4m-core/packages/utils/dist/src/questMaster.js
|
|
8178
|
-
var sanitizeId = (id
|
|
8179
|
-
|
|
8180
|
-
return sanitized || fallback;
|
|
7982
|
+
var sanitizeId = (id) => {
|
|
7983
|
+
return id.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9_.-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
8181
7984
|
};
|
|
8182
7985
|
var QuestMaster = class {
|
|
8183
7986
|
llm;
|
|
@@ -8205,12 +8008,10 @@ var QuestMaster = class {
|
|
|
8205
8008
|
}
|
|
8206
8009
|
return "Easy";
|
|
8207
8010
|
}
|
|
8208
|
-
async processQuestPlan(
|
|
8011
|
+
async processQuestPlan(questPlanText) {
|
|
8209
8012
|
try {
|
|
8210
|
-
if (!this.quest) {
|
|
8211
|
-
throw new Error("No quest context available");
|
|
8212
|
-
}
|
|
8213
8013
|
await this.onStatusUpdate(this.quest, "Processing quest plan...");
|
|
8014
|
+
this.logger.log("Processing quest plan:", questPlanText);
|
|
8214
8015
|
const defaultResponse = {
|
|
8215
8016
|
type: "narrative",
|
|
8216
8017
|
meta: {
|
|
@@ -8227,158 +8028,135 @@ var QuestMaster = class {
|
|
|
8227
8028
|
}
|
|
8228
8029
|
]
|
|
8229
8030
|
};
|
|
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
|
+
if (!this.quest) {
|
|
8047
|
+
throw new Error("No quest context available");
|
|
8048
|
+
}
|
|
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 = [];
|
|
8230
8055
|
let questResponse;
|
|
8231
|
-
if (
|
|
8232
|
-
|
|
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
|
+
}
|
|
8233
8080
|
questResponse = {
|
|
8234
8081
|
type: "quest_plan",
|
|
8235
8082
|
meta: {
|
|
8236
|
-
goal
|
|
8237
|
-
totalSteps:
|
|
8238
|
-
tags
|
|
8083
|
+
goal,
|
|
8084
|
+
totalSteps: validQuests.length,
|
|
8085
|
+
tags
|
|
8239
8086
|
},
|
|
8240
|
-
quests:
|
|
8087
|
+
quests: validQuests.map((quest) => ({
|
|
8241
8088
|
id: quest.id,
|
|
8089
|
+
// No fallback - we filtered for valid IDs
|
|
8242
8090
|
title: quest.title,
|
|
8091
|
+
// No fallback - we filtered for valid titles
|
|
8243
8092
|
description: quest.description,
|
|
8244
|
-
|
|
8093
|
+
// No fallback - we filtered for valid descriptions
|
|
8094
|
+
complexity: quest.complexity || "Medium",
|
|
8245
8095
|
status: "not_started",
|
|
8246
|
-
subQuests: quest.subQuests.map((sub) => ({
|
|
8096
|
+
subQuests: Array.isArray(quest.subQuests) ? quest.subQuests.filter((sub) => sub && sub.id && sub.title && !sub.title.startsWith("Subtask")).map((sub) => ({
|
|
8247
8097
|
id: sub.id,
|
|
8248
8098
|
title: sub.title,
|
|
8249
8099
|
status: "not_started"
|
|
8250
|
-
}))
|
|
8100
|
+
})) : []
|
|
8251
8101
|
}))
|
|
8252
8102
|
};
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
this.logger.log("Processing quest plan:", questPlanText);
|
|
8256
|
-
if (!questPlanText || typeof questPlanText !== "string") {
|
|
8257
|
-
this.logger.warn("Invalid questPlanText received:", questPlanText);
|
|
8258
|
-
if (this.quest) {
|
|
8259
|
-
this.quest.questMasterReply = JSON.stringify(defaultResponse);
|
|
8260
|
-
await this.db.quests.update({
|
|
8261
|
-
id: this.quest.id,
|
|
8262
|
-
questMasterReply: this.quest.questMasterReply,
|
|
8263
|
-
reply: null,
|
|
8264
|
-
replies: [],
|
|
8265
|
-
status: "done",
|
|
8266
|
-
type: "message"
|
|
8267
|
-
});
|
|
8268
|
-
}
|
|
8269
|
-
return;
|
|
8103
|
+
if (questResponse.quests.some((quest) => quest.subQuests.length === 0)) {
|
|
8104
|
+
throw new Error("Some quests have no valid subquests after filtering");
|
|
8270
8105
|
}
|
|
8271
|
-
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
const metaEndIndex = questPlanText.indexOf(metaEndTag, metaStartIndex);
|
|
8279
|
-
if (metaEndIndex !== -1) {
|
|
8280
|
-
const metaContent = questPlanText.slice(metaStartIndex + metaStartTag.length, metaEndIndex).trim();
|
|
8281
|
-
try {
|
|
8282
|
-
const jsonStartIndex = metaContent.indexOf("{");
|
|
8283
|
-
if (jsonStartIndex !== -1) {
|
|
8284
|
-
const metaData = JSON.parse(metaContent.slice(jsonStartIndex));
|
|
8285
|
-
goal = metaData.goal || goal;
|
|
8286
|
-
tags = Array.isArray(metaData.tags) ? metaData.tags : [];
|
|
8287
|
-
}
|
|
8288
|
-
} catch (err) {
|
|
8289
|
-
this.logger.error("Error parsing meta data:", err);
|
|
8106
|
+
} 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");
|
|
8290
8113
|
}
|
|
8291
|
-
|
|
8292
|
-
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
// No fallback - we filtered for valid IDs
|
|
8311
|
-
title: quest.title,
|
|
8312
|
-
// No fallback - we filtered for valid titles
|
|
8313
|
-
description: quest.description,
|
|
8314
|
-
// No fallback - we filtered for valid descriptions
|
|
8315
|
-
complexity: quest.complexity || "Medium",
|
|
8316
|
-
status: "not_started",
|
|
8317
|
-
subQuests: Array.isArray(quest.subQuests) ? quest.subQuests.filter((sub) => sub && sub.id && sub.title && !sub.title.startsWith("Subtask")).map((sub) => ({
|
|
8318
|
-
id: sub.id,
|
|
8319
|
-
title: sub.title,
|
|
8320
|
-
status: "not_started"
|
|
8321
|
-
})) : []
|
|
8322
|
-
}))
|
|
8323
|
-
};
|
|
8324
|
-
if (questResponse.quests.some((quest) => quest.subQuests.length === 0)) {
|
|
8325
|
-
throw new Error("Some quests have no valid subquests after filtering");
|
|
8326
|
-
}
|
|
8327
|
-
} else {
|
|
8328
|
-
try {
|
|
8329
|
-
const questPlan = JSON.parse(questPlanText);
|
|
8330
|
-
if (questPlan && questPlan.questChain && Array.isArray(questPlan.questChain)) {
|
|
8331
|
-
const validQuestChain = questPlan.questChain.filter((item) => item && item.quest && item.quest !== "Step 1" && item.details && item.details !== "No description available");
|
|
8332
|
-
if (validQuestChain.length === 0) {
|
|
8333
|
-
throw new Error("No valid quests found in quest chain");
|
|
8334
|
-
}
|
|
8335
|
-
questResponse = {
|
|
8336
|
-
type: "quest_plan",
|
|
8337
|
-
meta: {
|
|
8338
|
-
goal: questPlan.abstractObjective || "Process Request",
|
|
8339
|
-
totalSteps: validQuestChain.length
|
|
8340
|
-
},
|
|
8341
|
-
quests: validQuestChain.map((item, index) => ({
|
|
8342
|
-
id: `quest-${index + 1}`,
|
|
8343
|
-
title: item.quest,
|
|
8344
|
-
description: item.details,
|
|
8345
|
-
complexity: this.determineComplexity(item.details),
|
|
8346
|
-
status: "not_started",
|
|
8347
|
-
subQuests: []
|
|
8348
|
-
// This will trigger a retry since we require subquests
|
|
8349
|
-
}))
|
|
8350
|
-
};
|
|
8351
|
-
} else {
|
|
8352
|
-
if (!questPlanText.trim() || questPlanText.trim() === "Step 1") {
|
|
8353
|
-
throw new Error("Empty or invalid response received");
|
|
8354
|
-
}
|
|
8355
|
-
questResponse = {
|
|
8356
|
-
type: "narrative",
|
|
8357
|
-
meta: {
|
|
8358
|
-
goal: "Direct Response",
|
|
8359
|
-
totalSteps: 1
|
|
8360
|
-
},
|
|
8361
|
-
quests: [
|
|
8362
|
-
{
|
|
8363
|
-
id: "narrative-1",
|
|
8364
|
-
title: "Process Response",
|
|
8365
|
-
description: questPlanText.trim(),
|
|
8366
|
-
complexity: "Medium",
|
|
8367
|
-
subQuests: [
|
|
8368
|
-
{
|
|
8369
|
-
id: "narrative-1-1",
|
|
8370
|
-
title: "Review Response",
|
|
8371
|
-
status: "not_started"
|
|
8372
|
-
}
|
|
8373
|
-
]
|
|
8374
|
-
}
|
|
8375
|
-
]
|
|
8376
|
-
};
|
|
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");
|
|
8377
8133
|
}
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
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
|
+
};
|
|
8381
8156
|
}
|
|
8157
|
+
} catch (parseError) {
|
|
8158
|
+
this.logger.error("Error parsing quest plan JSON:", parseError);
|
|
8159
|
+
questResponse = defaultResponse;
|
|
8382
8160
|
}
|
|
8383
8161
|
}
|
|
8384
8162
|
if (!this.validateQuestResponse(questResponse)) {
|
|
@@ -8392,21 +8170,18 @@ var QuestMaster = class {
|
|
|
8392
8170
|
goal: questResponse.meta.goal,
|
|
8393
8171
|
userId: this.userId,
|
|
8394
8172
|
tags: questResponse.meta.tags || [],
|
|
8395
|
-
quests: questResponse.quests.map((quest
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
}))
|
|
8408
|
-
};
|
|
8409
|
-
})
|
|
8173
|
+
quests: questResponse.quests.map((quest) => ({
|
|
8174
|
+
id: sanitizeId(quest.id),
|
|
8175
|
+
title: quest.title,
|
|
8176
|
+
description: quest.description,
|
|
8177
|
+
complexity: quest.complexity,
|
|
8178
|
+
subQuests: quest.subQuests.map((sub) => ({
|
|
8179
|
+
id: sanitizeId(sub.id),
|
|
8180
|
+
title: sub.title,
|
|
8181
|
+
status: sub.status
|
|
8182
|
+
// questId intentionally omitted - will be set when task is started and linked to a chat message
|
|
8183
|
+
}))
|
|
8184
|
+
}))
|
|
8410
8185
|
});
|
|
8411
8186
|
this.quest.questMasterPlanId = questMasterPlan.id;
|
|
8412
8187
|
this.quest.reply = null;
|
|
@@ -8457,9 +8232,7 @@ var QuestMaster = class {
|
|
|
8457
8232
|
}
|
|
8458
8233
|
throw error;
|
|
8459
8234
|
} finally {
|
|
8460
|
-
|
|
8461
|
-
await this.onStatusUpdate(this.quest, null);
|
|
8462
|
-
}
|
|
8235
|
+
await this.onStatusUpdate(this.quest, null);
|
|
8463
8236
|
}
|
|
8464
8237
|
}
|
|
8465
8238
|
validateQuestResponse(response) {
|
|
@@ -8583,114 +8356,9 @@ var QuestMaster = class {
|
|
|
8583
8356
|
}
|
|
8584
8357
|
-->`;
|
|
8585
8358
|
}
|
|
8586
|
-
/**
|
|
8587
|
-
* Create a quest plan using GPT-5's function calling feature.
|
|
8588
|
-
* This method is used when the model is a GPT-5 variant that supports tools
|
|
8589
|
-
* but doesn't reliably follow HTML comment formatting.
|
|
8590
|
-
*
|
|
8591
|
-
* @param model - The GPT-5 model to use
|
|
8592
|
-
* @param prompt - The user's request to break down into quests
|
|
8593
|
-
* @returns The parsed quest plan result
|
|
8594
|
-
*/
|
|
8595
|
-
async createQuestPlanWithFunctionCalling(model, prompt, retryCount = 0) {
|
|
8596
|
-
const MAX_RETRIES = 2;
|
|
8597
|
-
const messages = [
|
|
8598
|
-
{
|
|
8599
|
-
role: "system",
|
|
8600
|
-
content: `You are the QuestMaster, an AI agent that breaks down complex tasks into manageable quests.
|
|
8601
|
-
|
|
8602
|
-
When given a user request, you MUST call the create_quest_plan function to structure your response.
|
|
8603
|
-
Do NOT respond with plain text - ALWAYS use the function call.
|
|
8604
|
-
|
|
8605
|
-
Guidelines:
|
|
8606
|
-
- Break down complex tasks into 3-7 main quests
|
|
8607
|
-
- Each quest needs 2-5 specific, actionable subquests
|
|
8608
|
-
- Make titles clear and action-oriented (e.g., "Set up database schema" not "Step 1")
|
|
8609
|
-
- Provide detailed descriptions explaining what needs to be done
|
|
8610
|
-
- Assess complexity accurately: Easy (< 1 hour), Medium (1-4 hours), Hard (> 4 hours)
|
|
8611
|
-
- Generate 2-5 relevant tags categorizing the work`
|
|
8612
|
-
},
|
|
8613
|
-
{ role: "user", content: prompt }
|
|
8614
|
-
];
|
|
8615
|
-
const toolDef = {
|
|
8616
|
-
toolFn: async (params) => JSON.stringify(params),
|
|
8617
|
-
// Not executed, just captured
|
|
8618
|
-
toolSchema: createQuestPlanToolSchema
|
|
8619
|
-
};
|
|
8620
|
-
const options = {
|
|
8621
|
-
temperature: retryCount > 0 ? 0.5 : 0.7,
|
|
8622
|
-
// Lower temperature for structured JSON outputs; even lower on retries
|
|
8623
|
-
n: 1,
|
|
8624
|
-
stream: false,
|
|
8625
|
-
tools: [toolDef],
|
|
8626
|
-
executeTools: false,
|
|
8627
|
-
// Don't execute, just capture the function call
|
|
8628
|
-
tool_choice: { type: "function", function: { name: "create_quest_plan" } },
|
|
8629
|
-
// Force function call
|
|
8630
|
-
parallel_tool_calls: false
|
|
8631
|
-
// Required for structured outputs
|
|
8632
|
-
};
|
|
8633
|
-
let functionResult = null;
|
|
8634
|
-
let lastError = null;
|
|
8635
|
-
try {
|
|
8636
|
-
await this.llm.complete(model, messages, options, async (text, completionInfo) => {
|
|
8637
|
-
if (completionInfo?.toolsUsed?.length) {
|
|
8638
|
-
const toolCall = completionInfo.toolsUsed[0];
|
|
8639
|
-
if (toolCall.name === "create_quest_plan" && toolCall.arguments) {
|
|
8640
|
-
this.logger.log("GPT-5 function call received, parsing arguments...");
|
|
8641
|
-
try {
|
|
8642
|
-
functionResult = parseQuestPlanFunctionCall(toolCall.arguments);
|
|
8643
|
-
} catch (parseError) {
|
|
8644
|
-
lastError = parseError instanceof Error ? parseError : new Error(String(parseError));
|
|
8645
|
-
this.logger.error("Failed to parse function call arguments:", parseError);
|
|
8646
|
-
}
|
|
8647
|
-
}
|
|
8648
|
-
}
|
|
8649
|
-
});
|
|
8650
|
-
} catch (error) {
|
|
8651
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
|
8652
|
-
this.logger.error("Error in GPT-5 function calling:", lastError);
|
|
8653
|
-
}
|
|
8654
|
-
if (!functionResult) {
|
|
8655
|
-
if (retryCount < MAX_RETRIES) {
|
|
8656
|
-
this.logger.warn(`GPT-5 did not return function call, retrying (attempt ${retryCount + 1}/${MAX_RETRIES})...`);
|
|
8657
|
-
return this.createQuestPlanWithFunctionCalling(model, prompt, retryCount + 1);
|
|
8658
|
-
}
|
|
8659
|
-
throw lastError || new Error("GPT-5 did not call create_quest_plan function after retries");
|
|
8660
|
-
}
|
|
8661
|
-
const result = functionResult;
|
|
8662
|
-
const questsWithoutSubquests = result.quests.filter((q) => !q.subQuests || q.subQuests.length === 0);
|
|
8663
|
-
if (questsWithoutSubquests.length > 0) {
|
|
8664
|
-
if (retryCount < MAX_RETRIES) {
|
|
8665
|
-
this.logger.warn(`Some quests missing subquests: ${questsWithoutSubquests.map((q) => q.id).join(", ")}, retrying...`);
|
|
8666
|
-
return this.createQuestPlanWithFunctionCalling(model, prompt, retryCount + 1);
|
|
8667
|
-
} else {
|
|
8668
|
-
this.logger.warn(`Returning quest plan with ${questsWithoutSubquests.length} quests missing subquests after max retries (${MAX_RETRIES}): ${questsWithoutSubquests.map((q) => q.id).join(", ")}`);
|
|
8669
|
-
}
|
|
8670
|
-
}
|
|
8671
|
-
this.logger.log("Successfully received GPT-5 function call result:", {
|
|
8672
|
-
goal: result.goal,
|
|
8673
|
-
questCount: result.quests.length,
|
|
8674
|
-
tags: result.tags
|
|
8675
|
-
});
|
|
8676
|
-
return result;
|
|
8677
|
-
}
|
|
8678
8359
|
async createQuestPlan(model, prompt) {
|
|
8679
8360
|
try {
|
|
8680
|
-
if (!this.quest) {
|
|
8681
|
-
throw new Error("No quest context available");
|
|
8682
|
-
}
|
|
8683
8361
|
await this.onStatusUpdate(this.quest, "Creating quest plan...");
|
|
8684
|
-
if (isGPT5ModelWithToolSupport(model)) {
|
|
8685
|
-
this.logger.log(`Using function calling approach for GPT-5 model: ${model}`);
|
|
8686
|
-
try {
|
|
8687
|
-
const result = await this.createQuestPlanWithFunctionCalling(model, prompt);
|
|
8688
|
-
await this.processQuestPlan(result);
|
|
8689
|
-
return;
|
|
8690
|
-
} catch (functionCallError) {
|
|
8691
|
-
this.logger.error("Function calling failed, falling back to HTML approach:", functionCallError);
|
|
8692
|
-
}
|
|
8693
|
-
}
|
|
8694
8362
|
const messages = [
|
|
8695
8363
|
{
|
|
8696
8364
|
role: "system",
|
|
@@ -10784,9 +10452,6 @@ export {
|
|
|
10784
10452
|
sendToConnection,
|
|
10785
10453
|
ClientMessageSender,
|
|
10786
10454
|
OpenaiModerationsService,
|
|
10787
|
-
isGPT5ModelWithToolSupport,
|
|
10788
|
-
createQuestPlanToolSchema,
|
|
10789
|
-
parseQuestPlanFunctionCall,
|
|
10790
10455
|
QuestMaster,
|
|
10791
10456
|
OpenAIImageService,
|
|
10792
10457
|
TestImageService,
|