@bike4mind/cli 0.2.1-quest-file-uploads.17007 → 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.
- package/dist/{chunk-QXGU6KYI.js → chunk-44WCHZA2.js} +1 -1
- package/dist/{chunk-F3ETXO5N.js → chunk-KDBSH6HC.js} +1 -1
- package/dist/{chunk-U3GPYBTD.js → chunk-NH74I6GX.js} +390 -117
- package/dist/{chunk-LZMRYJ3B.js → chunk-O2622ACK.js} +13 -5
- package/dist/{create-YUYXTEIS.js → create-LKM7JKFD.js} +2 -2
- package/dist/index.js +739 -215
- package/dist/{mementoService-2BDIT6PH.js → mementoService-EQIPY6HP.js} +2 -2
- package/dist/{src-VLP2EHKE.js → src-U3N2PGNX.js} +7 -1
- package/dist/{subtractCredits-NNYIS5XZ.js → subtractCredits-7PKKJISU.js} +2 -2
- package/package.json +13 -7
|
@@ -610,6 +610,10 @@ var AnthropicBackend = class {
|
|
|
610
610
|
}
|
|
611
611
|
if (collectedContent[event.index] && collectedContent[event.index].type === "tool_use") {
|
|
612
612
|
}
|
|
613
|
+
} else if ("delta" in event && event.delta.type === "signature_delta") {
|
|
614
|
+
if (collectedContent[event.index] && collectedContent[event.index].type === "thinking") {
|
|
615
|
+
collectedContent[event.index].signature = event.delta.signature;
|
|
616
|
+
}
|
|
613
617
|
}
|
|
614
618
|
} else if (event.type === "content_block_stop") {
|
|
615
619
|
if (isInThinkingBlock) {
|
|
@@ -792,14 +796,11 @@ var AnthropicBackend = class {
|
|
|
792
796
|
}
|
|
793
797
|
pushToolMessages(messages, tool, result, previousMessage) {
|
|
794
798
|
if (this.isThinkingEnabled && this.lastAssistantContent.length > 0) {
|
|
795
|
-
const contentWithoutThinking = this.lastAssistantContent.filter((block) => {
|
|
796
|
-
return block.type !== "thinking";
|
|
797
|
-
});
|
|
798
799
|
messages.push({
|
|
799
800
|
role: "assistant",
|
|
800
|
-
content:
|
|
801
|
+
content: this.lastAssistantContent
|
|
801
802
|
});
|
|
802
|
-
this.logger.debug(`[AnthropicBackend]
|
|
803
|
+
this.logger.debug(`[AnthropicBackend] Including ${this.lastAssistantContent.length} content blocks (thinking + tool_use) in assistant message`);
|
|
803
804
|
} else {
|
|
804
805
|
messages.push({
|
|
805
806
|
role: "assistant",
|
|
@@ -1118,8 +1119,12 @@ var BaseBedrockBackend = class {
|
|
|
1118
1119
|
await callback(streamedText, { inputTokens, outputTokens, toolsUsed });
|
|
1119
1120
|
}
|
|
1120
1121
|
} catch (error) {
|
|
1121
|
-
console.error(`[BaseBedrockBackend] Error invoking model ${model}:`, error);
|
|
1122
1122
|
if (error instanceof Error) {
|
|
1123
|
+
if (error.message.includes("aborted")) {
|
|
1124
|
+
console.log("[BaseBedrockBackend] Request aborted, skipping error logging");
|
|
1125
|
+
throw error;
|
|
1126
|
+
}
|
|
1127
|
+
console.error(`[BaseBedrockBackend] Error invoking model ${model}:`, error);
|
|
1123
1128
|
console.error(`[BaseBedrockBackend] Error details:`, {
|
|
1124
1129
|
name: error.name,
|
|
1125
1130
|
message: error.message,
|
|
@@ -4107,6 +4112,12 @@ var OpenAIBackend = class {
|
|
|
4107
4112
|
}
|
|
4108
4113
|
if (options.tools?.length) {
|
|
4109
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
|
+
}
|
|
4110
4121
|
}
|
|
4111
4122
|
const response = await this._api.chat.completions.create(parameters, {
|
|
4112
4123
|
signal: options.abortSignal
|
|
@@ -7973,6 +7984,147 @@ function extractQuestMasterData(reply, options = {}) {
|
|
|
7973
7984
|
return questMasterData;
|
|
7974
7985
|
}
|
|
7975
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
|
+
|
|
7976
8128
|
// ../../b4m-core/packages/utils/dist/src/questMaster.js
|
|
7977
8129
|
var sanitizeId = (id) => {
|
|
7978
8130
|
return id.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9_.-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -8003,10 +8155,9 @@ var QuestMaster = class {
|
|
|
8003
8155
|
}
|
|
8004
8156
|
return "Easy";
|
|
8005
8157
|
}
|
|
8006
|
-
async processQuestPlan(
|
|
8158
|
+
async processQuestPlan(input) {
|
|
8007
8159
|
try {
|
|
8008
8160
|
await this.onStatusUpdate(this.quest, "Processing quest plan...");
|
|
8009
|
-
this.logger.log("Processing quest plan:", questPlanText);
|
|
8010
8161
|
const defaultResponse = {
|
|
8011
8162
|
type: "narrative",
|
|
8012
8163
|
meta: {
|
|
@@ -8023,135 +8174,161 @@ var QuestMaster = class {
|
|
|
8023
8174
|
}
|
|
8024
8175
|
]
|
|
8025
8176
|
};
|
|
8026
|
-
if (!questPlanText || typeof questPlanText !== "string") {
|
|
8027
|
-
this.logger.warn("Invalid questPlanText received:", questPlanText);
|
|
8028
|
-
if (this.quest) {
|
|
8029
|
-
this.quest.questMasterReply = JSON.stringify(defaultResponse);
|
|
8030
|
-
await this.db.quests.update({
|
|
8031
|
-
id: this.quest.id,
|
|
8032
|
-
questMasterReply: this.quest.questMasterReply,
|
|
8033
|
-
reply: null,
|
|
8034
|
-
replies: [],
|
|
8035
|
-
status: "done",
|
|
8036
|
-
type: "message"
|
|
8037
|
-
});
|
|
8038
|
-
}
|
|
8039
|
-
return;
|
|
8040
|
-
}
|
|
8041
8177
|
if (!this.quest) {
|
|
8042
8178
|
throw new Error("No quest context available");
|
|
8043
8179
|
}
|
|
8044
|
-
const extracted = extractQuestMasterData(questPlanText, { logger: this.logger });
|
|
8045
|
-
const metaStartTag = "<!--QuestMasterMeta";
|
|
8046
|
-
const metaEndTag = "-->";
|
|
8047
|
-
const metaStartIndex = questPlanText.indexOf(metaStartTag);
|
|
8048
|
-
let goal = "Quest Plan";
|
|
8049
|
-
let tags = [];
|
|
8050
8180
|
let questResponse;
|
|
8051
|
-
if (
|
|
8052
|
-
|
|
8053
|
-
if (metaEndIndex !== -1) {
|
|
8054
|
-
const metaContent = questPlanText.slice(metaStartIndex + metaStartTag.length, metaEndIndex).trim();
|
|
8055
|
-
try {
|
|
8056
|
-
const jsonStartIndex = metaContent.indexOf("{");
|
|
8057
|
-
if (jsonStartIndex !== -1) {
|
|
8058
|
-
const metaData = JSON.parse(metaContent.slice(jsonStartIndex));
|
|
8059
|
-
goal = metaData.goal || goal;
|
|
8060
|
-
tags = Array.isArray(metaData.tags) ? metaData.tags : [];
|
|
8061
|
-
}
|
|
8062
|
-
} catch (err) {
|
|
8063
|
-
this.logger.error("Error parsing meta data:", err);
|
|
8064
|
-
}
|
|
8065
|
-
}
|
|
8066
|
-
}
|
|
8067
|
-
if (extracted.length > 0) {
|
|
8068
|
-
this.logger.log("Successfully extracted QuestMaster data:", extracted);
|
|
8069
|
-
await this.onStatusUpdate(this.quest, "Extracted QuestMaster data");
|
|
8070
|
-
const validQuests = extracted.filter((quest) => quest !== null && typeof quest === "object" && quest.id && quest.title && quest.title !== "Step 1" && // Explicitly filter out generic Step 1
|
|
8071
|
-
quest.description && quest.description !== "No description available");
|
|
8072
|
-
if (validQuests.length === 0) {
|
|
8073
|
-
throw new Error("No valid quests found after filtering");
|
|
8074
|
-
}
|
|
8181
|
+
if (typeof input === "object") {
|
|
8182
|
+
this.logger.log("Processing quest plan from function calling result");
|
|
8075
8183
|
questResponse = {
|
|
8076
8184
|
type: "quest_plan",
|
|
8077
8185
|
meta: {
|
|
8078
|
-
goal,
|
|
8079
|
-
totalSteps:
|
|
8080
|
-
tags
|
|
8186
|
+
goal: input.goal,
|
|
8187
|
+
totalSteps: input.quests.length,
|
|
8188
|
+
tags: input.tags
|
|
8081
8189
|
},
|
|
8082
|
-
quests:
|
|
8190
|
+
quests: input.quests.map((quest) => ({
|
|
8083
8191
|
id: quest.id,
|
|
8084
|
-
// No fallback - we filtered for valid IDs
|
|
8085
8192
|
title: quest.title,
|
|
8086
|
-
// No fallback - we filtered for valid titles
|
|
8087
8193
|
description: quest.description,
|
|
8088
|
-
|
|
8089
|
-
complexity: quest.complexity || "Medium",
|
|
8194
|
+
complexity: quest.complexity,
|
|
8090
8195
|
status: "not_started",
|
|
8091
|
-
subQuests:
|
|
8196
|
+
subQuests: quest.subQuests.map((sub) => ({
|
|
8092
8197
|
id: sub.id,
|
|
8093
8198
|
title: sub.title,
|
|
8094
8199
|
status: "not_started"
|
|
8095
|
-
}))
|
|
8200
|
+
}))
|
|
8096
8201
|
}))
|
|
8097
8202
|
};
|
|
8098
|
-
if (questResponse.quests.some((quest) => quest.subQuests.length === 0)) {
|
|
8099
|
-
throw new Error("Some quests have no valid subquests after filtering");
|
|
8100
|
-
}
|
|
8101
8203
|
} else {
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
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);
|
|
8108
8240
|
}
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
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
|
+
};
|
|
8128
8327
|
}
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
goal: "Direct Response",
|
|
8133
|
-
totalSteps: 1
|
|
8134
|
-
},
|
|
8135
|
-
quests: [
|
|
8136
|
-
{
|
|
8137
|
-
id: "narrative-1",
|
|
8138
|
-
title: "Process Response",
|
|
8139
|
-
description: questPlanText.trim(),
|
|
8140
|
-
complexity: "Medium",
|
|
8141
|
-
subQuests: [
|
|
8142
|
-
{
|
|
8143
|
-
id: "narrative-1-1",
|
|
8144
|
-
title: "Review Response",
|
|
8145
|
-
status: "not_started"
|
|
8146
|
-
}
|
|
8147
|
-
]
|
|
8148
|
-
}
|
|
8149
|
-
]
|
|
8150
|
-
};
|
|
8328
|
+
} catch (parseError) {
|
|
8329
|
+
this.logger.error("Error parsing quest plan JSON:", parseError);
|
|
8330
|
+
questResponse = defaultResponse;
|
|
8151
8331
|
}
|
|
8152
|
-
} catch (parseError) {
|
|
8153
|
-
this.logger.error("Error parsing quest plan JSON:", parseError);
|
|
8154
|
-
questResponse = defaultResponse;
|
|
8155
8332
|
}
|
|
8156
8333
|
}
|
|
8157
8334
|
if (!this.validateQuestResponse(questResponse)) {
|
|
@@ -8351,9 +8528,102 @@ var QuestMaster = class {
|
|
|
8351
8528
|
}
|
|
8352
8529
|
-->`;
|
|
8353
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
|
+
}
|
|
8354
8614
|
async createQuestPlan(model, prompt) {
|
|
8355
8615
|
try {
|
|
8356
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
|
+
}
|
|
8357
8627
|
const messages = [
|
|
8358
8628
|
{
|
|
8359
8629
|
role: "system",
|
|
@@ -9952,7 +10222,7 @@ function shouldTriggerFallback(error) {
|
|
|
9952
10222
|
return true;
|
|
9953
10223
|
}
|
|
9954
10224
|
}
|
|
9955
|
-
if ("code" in error && error.code === "ECONNRESET") {
|
|
10225
|
+
if ("code" in error && error.code === "ECONNRESET" && !message.includes("aborted")) {
|
|
9956
10226
|
return true;
|
|
9957
10227
|
}
|
|
9958
10228
|
if (error.name === "TypeError" && message.includes("terminated")) {
|
|
@@ -10447,6 +10717,9 @@ export {
|
|
|
10447
10717
|
sendToConnection,
|
|
10448
10718
|
ClientMessageSender,
|
|
10449
10719
|
OpenaiModerationsService,
|
|
10720
|
+
isGPT5ModelWithToolSupport,
|
|
10721
|
+
createQuestPlanToolSchema,
|
|
10722
|
+
parseQuestPlanFunctionCall,
|
|
10450
10723
|
QuestMaster,
|
|
10451
10724
|
OpenAIImageService,
|
|
10452
10725
|
TestImageService,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
BadRequestError,
|
|
4
4
|
secureParameters
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-NH74I6GX.js";
|
|
6
6
|
import {
|
|
7
7
|
GenericCreditDeductTransaction,
|
|
8
8
|
ImageEditUsageTransaction,
|
|
@@ -22,12 +22,20 @@ var SubtractCreditsSchema = z.discriminatedUnion("type", [
|
|
|
22
22
|
ImageEditUsageTransaction.omit({ createdAt: true, updatedAt: true }),
|
|
23
23
|
TransferCreditTransaction.omit({ createdAt: true, updatedAt: true })
|
|
24
24
|
]);
|
|
25
|
-
async function subtractCredits(parameters, { db, creditHolderMethods }) {
|
|
25
|
+
async function subtractCredits(parameters, { db, creditHolderMethods, skipBalanceUpdate, currentCreditHolder }) {
|
|
26
26
|
const params = secureParameters(parameters, SubtractCreditsSchema);
|
|
27
27
|
const { ownerId, ownerType, credits, type, description, metadata } = params;
|
|
28
|
-
|
|
29
|
-
if (
|
|
30
|
-
|
|
28
|
+
let updatedEntity;
|
|
29
|
+
if (skipBalanceUpdate) {
|
|
30
|
+
if (!currentCreditHolder) {
|
|
31
|
+
throw new BadRequestError("currentCreditHolder is required when skipBalanceUpdate is true");
|
|
32
|
+
}
|
|
33
|
+
updatedEntity = currentCreditHolder;
|
|
34
|
+
} else {
|
|
35
|
+
updatedEntity = await creditHolderMethods.incrementCredits(ownerId, -credits);
|
|
36
|
+
if (!updatedEntity) {
|
|
37
|
+
throw new BadRequestError("Failed to update credits");
|
|
38
|
+
}
|
|
31
39
|
}
|
|
32
40
|
if (type === "generic_deduct") {
|
|
33
41
|
await db.creditTransactions.createTransaction("generic_deduct", {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createFabFile,
|
|
4
4
|
createFabFileSchema
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
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";
|