@probelabs/probe 0.6.0-rc162 → 0.6.0-rc164

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.
@@ -48,6 +48,7 @@ import {
48
48
  isJsonSchema,
49
49
  validateJsonResponse,
50
50
  createJsonCorrectionPrompt,
51
+ generateSchemaInstructions,
51
52
  isJsonSchemaDefinition,
52
53
  createSchemaDefinitionCorrectionPrompt,
53
54
  validateAndFixMermaidResponse
@@ -1455,11 +1456,18 @@ When troubleshooting:
1455
1456
 
1456
1457
  // Create user message with optional image support
1457
1458
  let userMessage = { role: 'user', content: message.trim() };
1458
-
1459
+
1460
+ // If schema is provided, prepend JSON format requirement to user message
1461
+ if (options.schema && !options._schemaFormatted) {
1462
+ const schemaInstructions = generateSchemaInstructions(options.schema, { debug: this.debug });
1463
+ userMessage.content = message.trim() + schemaInstructions;
1464
+ }
1465
+
1459
1466
  // If images are provided, use multi-modal message format
1460
1467
  if (images && images.length > 0) {
1468
+ const textContent = userMessage.content;
1461
1469
  userMessage.content = [
1462
- { type: 'text', text: message.trim() },
1470
+ { type: 'text', text: textContent },
1463
1471
  ...images.map(image => ({
1464
1472
  type: 'image',
1465
1473
  image: image
@@ -2001,29 +2009,8 @@ When troubleshooting:
2001
2009
  // Add assistant response and ask for tool usage
2002
2010
  currentMessages.push({ role: 'assistant', content: assistantResponseContent });
2003
2011
 
2004
- // Build appropriate reminder message based on whether schema is provided
2005
- let reminderContent;
2006
- if (options.schema) { // Apply for ANY schema, not just JSON schemas
2007
- // When schema is provided, AI must use attempt_completion to trigger schema formatting
2008
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
2009
-
2010
- Remember: Use proper XML format with BOTH opening and closing tags:
2011
-
2012
- <tool_name>
2013
- <parameter>value</parameter>
2014
- </tool_name>
2015
-
2016
- IMPORTANT: A schema was provided for the final output format.
2017
-
2018
- You MUST use attempt_completion to provide your answer:
2019
- <attempt_completion>
2020
- [Your complete answer here - provide in natural language, it will be automatically formatted to match the schema]
2021
- </attempt_completion>
2022
-
2023
- Your response will be automatically formatted to JSON. You can provide your answer in natural language or as JSON - either will work.`;
2024
- } else {
2025
- // Standard reminder without schema
2026
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
2012
+ // Standard reminder - schema was already provided in initial message
2013
+ const reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
2027
2014
 
2028
2015
  Remember: Use proper XML format with BOTH opening and closing tags:
2029
2016
 
@@ -2035,7 +2022,6 @@ Or for quick completion if your previous response was already correct and comple
2035
2022
  <attempt_complete>
2036
2023
 
2037
2024
  IMPORTANT: When using <attempt_complete>, this must be the ONLY content in your response. No additional text, explanations, or other content should be included. This tag signals to reuse your previous response as the final answer.`;
2038
- }
2039
2025
 
2040
2026
  currentMessages.push({
2041
2027
  role: 'user',
@@ -54264,6 +54264,8 @@ __export(schemaUtils_exports, {
54264
54264
  createSchemaDefinitionCorrectionPrompt: () => createSchemaDefinitionCorrectionPrompt,
54265
54265
  decodeHtmlEntities: () => decodeHtmlEntities,
54266
54266
  extractMermaidFromMarkdown: () => extractMermaidFromMarkdown,
54267
+ generateExampleFromSchema: () => generateExampleFromSchema,
54268
+ generateSchemaInstructions: () => generateSchemaInstructions,
54267
54269
  isJsonSchema: () => isJsonSchema,
54268
54270
  isJsonSchemaDefinition: () => isJsonSchemaDefinition,
54269
54271
  isMermaidSchema: () => isMermaidSchema,
@@ -54276,6 +54278,54 @@ __export(schemaUtils_exports, {
54276
54278
  validateMermaidResponse: () => validateMermaidResponse,
54277
54279
  validateXmlResponse: () => validateXmlResponse
54278
54280
  });
54281
+ function generateExampleFromSchema(schema, options = {}) {
54282
+ const { debug = false } = options;
54283
+ try {
54284
+ const parsedSchema = typeof schema === "string" ? JSON.parse(schema) : schema;
54285
+ if (parsedSchema.type !== "object" || !parsedSchema.properties) {
54286
+ return null;
54287
+ }
54288
+ const exampleObj = {};
54289
+ for (const [key, value] of Object.entries(parsedSchema.properties)) {
54290
+ if (value.type === "boolean") {
54291
+ exampleObj[key] = false;
54292
+ } else if (value.type === "number") {
54293
+ exampleObj[key] = 0;
54294
+ } else if (value.type === "string") {
54295
+ exampleObj[key] = value.description || "your answer here";
54296
+ } else if (value.type === "array") {
54297
+ exampleObj[key] = [];
54298
+ } else {
54299
+ exampleObj[key] = {};
54300
+ }
54301
+ }
54302
+ return exampleObj;
54303
+ } catch (e) {
54304
+ if (debug) {
54305
+ console.error("[DEBUG] generateExampleFromSchema: Failed to parse schema:", e.message);
54306
+ }
54307
+ return null;
54308
+ }
54309
+ }
54310
+ function generateSchemaInstructions(schema, options = {}) {
54311
+ const { debug = false } = options;
54312
+ let instructions = "\n\nIMPORTANT: When you provide your final answer using attempt_completion, you MUST format it as valid JSON matching this schema:\n\n";
54313
+ try {
54314
+ const parsedSchema = typeof schema === "string" ? JSON.parse(schema) : schema;
54315
+ instructions += `${JSON.stringify(parsedSchema, null, 2)}
54316
+
54317
+ `;
54318
+ } catch (e) {
54319
+ if (debug) {
54320
+ console.error("[DEBUG] generateSchemaInstructions: Failed to parse schema:", e.message);
54321
+ }
54322
+ instructions += `${schema}
54323
+
54324
+ `;
54325
+ }
54326
+ instructions += "Your response inside attempt_completion must be ONLY valid JSON - no plain text, no explanations, no markdown.\n\nIMPORTANT: First complete the requested analysis/task thoroughly, then provide your final answer in the JSON format above.";
54327
+ return instructions;
54328
+ }
54279
54329
  function enforceNoAdditionalProperties(schema) {
54280
54330
  if (!schema || typeof schema !== "object") {
54281
54331
  return schema;
@@ -58305,9 +58355,14 @@ You are working with a repository located at: ${searchDirectory}
58305
58355
  });
58306
58356
  const systemMessage = await this.getSystemMessage();
58307
58357
  let userMessage = { role: "user", content: message.trim() };
58358
+ if (options.schema && !options._schemaFormatted) {
58359
+ const schemaInstructions = generateSchemaInstructions(options.schema, { debug: this.debug });
58360
+ userMessage.content = message.trim() + schemaInstructions;
58361
+ }
58308
58362
  if (images && images.length > 0) {
58363
+ const textContent = userMessage.content;
58309
58364
  userMessage.content = [
58310
- { type: "text", text: message.trim() },
58365
+ { type: "text", text: textContent },
58311
58366
  ...images.map((image) => ({
58312
58367
  type: "image",
58313
58368
  image
@@ -58727,26 +58782,7 @@ Error: Unknown tool '${toolName}'. Available tools: ${allAvailableTools.join(",
58727
58782
  break;
58728
58783
  }
58729
58784
  currentMessages.push({ role: "assistant", content: assistantResponseContent });
58730
- let reminderContent;
58731
- if (options.schema) {
58732
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
58733
-
58734
- Remember: Use proper XML format with BOTH opening and closing tags:
58735
-
58736
- <tool_name>
58737
- <parameter>value</parameter>
58738
- </tool_name>
58739
-
58740
- IMPORTANT: A schema was provided for the final output format.
58741
-
58742
- You MUST use attempt_completion to provide your answer:
58743
- <attempt_completion>
58744
- [Your complete answer here - provide in natural language, it will be automatically formatted to match the schema]
58745
- </attempt_completion>
58746
-
58747
- Your response will be automatically formatted to JSON. You can provide your answer in natural language or as JSON - either will work.`;
58748
- } else {
58749
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
58785
+ const reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
58750
58786
 
58751
58787
  Remember: Use proper XML format with BOTH opening and closing tags:
58752
58788
 
@@ -58758,7 +58794,6 @@ Or for quick completion if your previous response was already correct and comple
58758
58794
  <attempt_complete>
58759
58795
 
58760
58796
  IMPORTANT: When using <attempt_complete>, this must be the ONLY content in your response. No additional text, explanations, or other content should be included. This tag signals to reuse your previous response as the final answer.`;
58761
- }
58762
58797
  currentMessages.push({
58763
58798
  role: "user",
58764
58799
  content: reminderContent
@@ -7,6 +7,74 @@ import { createMessagePreview } from '../tools/common.js';
7
7
  import { validate, fixText, extractMermaidBlocks } from '@probelabs/maid';
8
8
  import Ajv from 'ajv';
9
9
 
10
+ /**
11
+ * Generate an example JSON object from a JSON schema
12
+ * @param {Object|string} schema - JSON schema object or string
13
+ * @param {Object} options - Options for generation
14
+ * @param {boolean} [options.debug=false] - Enable debug logging
15
+ * @returns {Object|null} - Example object, or null if schema cannot be processed
16
+ */
17
+ export function generateExampleFromSchema(schema, options = {}) {
18
+ const { debug = false } = options;
19
+
20
+ try {
21
+ const parsedSchema = typeof schema === 'string' ? JSON.parse(schema) : schema;
22
+
23
+ if (parsedSchema.type !== 'object' || !parsedSchema.properties) {
24
+ return null;
25
+ }
26
+
27
+ const exampleObj = {};
28
+ for (const [key, value] of Object.entries(parsedSchema.properties)) {
29
+ if (value.type === 'boolean') {
30
+ exampleObj[key] = false;
31
+ } else if (value.type === 'number') {
32
+ exampleObj[key] = 0;
33
+ } else if (value.type === 'string') {
34
+ exampleObj[key] = value.description || 'your answer here';
35
+ } else if (value.type === 'array') {
36
+ exampleObj[key] = [];
37
+ } else {
38
+ exampleObj[key] = {};
39
+ }
40
+ }
41
+
42
+ return exampleObj;
43
+ } catch (e) {
44
+ if (debug) {
45
+ console.error('[DEBUG] generateExampleFromSchema: Failed to parse schema:', e.message);
46
+ }
47
+ return null;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Generate schema instructions for AI to follow
53
+ * @param {Object|string} schema - JSON schema object or string
54
+ * @param {Object} options - Options for generation
55
+ * @param {boolean} [options.debug=false] - Enable debug logging
56
+ * @returns {string} - Formatted schema instructions
57
+ */
58
+ export function generateSchemaInstructions(schema, options = {}) {
59
+ const { debug = false } = options;
60
+
61
+ let instructions = '\n\nIMPORTANT: When you provide your final answer using attempt_completion, you MUST format it as valid JSON matching this schema:\n\n';
62
+
63
+ try {
64
+ const parsedSchema = typeof schema === 'string' ? JSON.parse(schema) : schema;
65
+ instructions += `${JSON.stringify(parsedSchema, null, 2)}\n\n`;
66
+ } catch (e) {
67
+ if (debug) {
68
+ console.error('[DEBUG] generateSchemaInstructions: Failed to parse schema:', e.message);
69
+ }
70
+ instructions += `${schema}\n\n`;
71
+ }
72
+
73
+ instructions += 'Your response inside attempt_completion must be ONLY valid JSON - no plain text, no explanations, no markdown.\n\nIMPORTANT: First complete the requested analysis/task thoroughly, then provide your final answer in the JSON format above.';
74
+
75
+ return instructions;
76
+ }
77
+
10
78
  /**
11
79
  * Recursively apply additionalProperties: false to all object schemas
12
80
  * This ensures strict validation at all nesting levels
@@ -79944,6 +79944,8 @@ __export(schemaUtils_exports, {
79944
79944
  createSchemaDefinitionCorrectionPrompt: () => createSchemaDefinitionCorrectionPrompt,
79945
79945
  decodeHtmlEntities: () => decodeHtmlEntities,
79946
79946
  extractMermaidFromMarkdown: () => extractMermaidFromMarkdown,
79947
+ generateExampleFromSchema: () => generateExampleFromSchema,
79948
+ generateSchemaInstructions: () => generateSchemaInstructions,
79947
79949
  isJsonSchema: () => isJsonSchema,
79948
79950
  isJsonSchemaDefinition: () => isJsonSchemaDefinition,
79949
79951
  isMermaidSchema: () => isMermaidSchema,
@@ -79956,6 +79958,54 @@ __export(schemaUtils_exports, {
79956
79958
  validateMermaidResponse: () => validateMermaidResponse,
79957
79959
  validateXmlResponse: () => validateXmlResponse
79958
79960
  });
79961
+ function generateExampleFromSchema(schema, options = {}) {
79962
+ const { debug = false } = options;
79963
+ try {
79964
+ const parsedSchema = typeof schema === "string" ? JSON.parse(schema) : schema;
79965
+ if (parsedSchema.type !== "object" || !parsedSchema.properties) {
79966
+ return null;
79967
+ }
79968
+ const exampleObj = {};
79969
+ for (const [key, value] of Object.entries(parsedSchema.properties)) {
79970
+ if (value.type === "boolean") {
79971
+ exampleObj[key] = false;
79972
+ } else if (value.type === "number") {
79973
+ exampleObj[key] = 0;
79974
+ } else if (value.type === "string") {
79975
+ exampleObj[key] = value.description || "your answer here";
79976
+ } else if (value.type === "array") {
79977
+ exampleObj[key] = [];
79978
+ } else {
79979
+ exampleObj[key] = {};
79980
+ }
79981
+ }
79982
+ return exampleObj;
79983
+ } catch (e3) {
79984
+ if (debug) {
79985
+ console.error("[DEBUG] generateExampleFromSchema: Failed to parse schema:", e3.message);
79986
+ }
79987
+ return null;
79988
+ }
79989
+ }
79990
+ function generateSchemaInstructions(schema, options = {}) {
79991
+ const { debug = false } = options;
79992
+ let instructions = "\n\nIMPORTANT: When you provide your final answer using attempt_completion, you MUST format it as valid JSON matching this schema:\n\n";
79993
+ try {
79994
+ const parsedSchema = typeof schema === "string" ? JSON.parse(schema) : schema;
79995
+ instructions += `${JSON.stringify(parsedSchema, null, 2)}
79996
+
79997
+ `;
79998
+ } catch (e3) {
79999
+ if (debug) {
80000
+ console.error("[DEBUG] generateSchemaInstructions: Failed to parse schema:", e3.message);
80001
+ }
80002
+ instructions += `${schema}
80003
+
80004
+ `;
80005
+ }
80006
+ instructions += "Your response inside attempt_completion must be ONLY valid JSON - no plain text, no explanations, no markdown.\n\nIMPORTANT: First complete the requested analysis/task thoroughly, then provide your final answer in the JSON format above.";
80007
+ return instructions;
80008
+ }
79959
80009
  function enforceNoAdditionalProperties(schema) {
79960
80010
  if (!schema || typeof schema !== "object") {
79961
80011
  return schema;
@@ -83985,9 +84035,14 @@ You are working with a repository located at: ${searchDirectory}
83985
84035
  });
83986
84036
  const systemMessage = await this.getSystemMessage();
83987
84037
  let userMessage = { role: "user", content: message.trim() };
84038
+ if (options.schema && !options._schemaFormatted) {
84039
+ const schemaInstructions = generateSchemaInstructions(options.schema, { debug: this.debug });
84040
+ userMessage.content = message.trim() + schemaInstructions;
84041
+ }
83988
84042
  if (images && images.length > 0) {
84043
+ const textContent = userMessage.content;
83989
84044
  userMessage.content = [
83990
- { type: "text", text: message.trim() },
84045
+ { type: "text", text: textContent },
83991
84046
  ...images.map((image) => ({
83992
84047
  type: "image",
83993
84048
  image
@@ -84407,26 +84462,7 @@ Error: Unknown tool '${toolName}'. Available tools: ${allAvailableTools.join(",
84407
84462
  break;
84408
84463
  }
84409
84464
  currentMessages.push({ role: "assistant", content: assistantResponseContent });
84410
- let reminderContent;
84411
- if (options.schema) {
84412
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
84413
-
84414
- Remember: Use proper XML format with BOTH opening and closing tags:
84415
-
84416
- <tool_name>
84417
- <parameter>value</parameter>
84418
- </tool_name>
84419
-
84420
- IMPORTANT: A schema was provided for the final output format.
84421
-
84422
- You MUST use attempt_completion to provide your answer:
84423
- <attempt_completion>
84424
- [Your complete answer here - provide in natural language, it will be automatically formatted to match the schema]
84425
- </attempt_completion>
84426
-
84427
- Your response will be automatically formatted to JSON. You can provide your answer in natural language or as JSON - either will work.`;
84428
- } else {
84429
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
84465
+ const reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
84430
84466
 
84431
84467
  Remember: Use proper XML format with BOTH opening and closing tags:
84432
84468
 
@@ -84438,7 +84474,6 @@ Or for quick completion if your previous response was already correct and comple
84438
84474
  <attempt_complete>
84439
84475
 
84440
84476
  IMPORTANT: When using <attempt_complete>, this must be the ONLY content in your response. No additional text, explanations, or other content should be included. This tag signals to reuse your previous response as the final answer.`;
84441
- }
84442
84477
  currentMessages.push({
84443
84478
  role: "user",
84444
84479
  content: reminderContent
package/cjs/index.cjs CHANGED
@@ -77686,6 +77686,8 @@ __export(schemaUtils_exports, {
77686
77686
  createSchemaDefinitionCorrectionPrompt: () => createSchemaDefinitionCorrectionPrompt,
77687
77687
  decodeHtmlEntities: () => decodeHtmlEntities,
77688
77688
  extractMermaidFromMarkdown: () => extractMermaidFromMarkdown,
77689
+ generateExampleFromSchema: () => generateExampleFromSchema,
77690
+ generateSchemaInstructions: () => generateSchemaInstructions,
77689
77691
  isJsonSchema: () => isJsonSchema,
77690
77692
  isJsonSchemaDefinition: () => isJsonSchemaDefinition,
77691
77693
  isMermaidSchema: () => isMermaidSchema,
@@ -77698,6 +77700,54 @@ __export(schemaUtils_exports, {
77698
77700
  validateMermaidResponse: () => validateMermaidResponse,
77699
77701
  validateXmlResponse: () => validateXmlResponse
77700
77702
  });
77703
+ function generateExampleFromSchema(schema, options = {}) {
77704
+ const { debug = false } = options;
77705
+ try {
77706
+ const parsedSchema = typeof schema === "string" ? JSON.parse(schema) : schema;
77707
+ if (parsedSchema.type !== "object" || !parsedSchema.properties) {
77708
+ return null;
77709
+ }
77710
+ const exampleObj = {};
77711
+ for (const [key, value] of Object.entries(parsedSchema.properties)) {
77712
+ if (value.type === "boolean") {
77713
+ exampleObj[key] = false;
77714
+ } else if (value.type === "number") {
77715
+ exampleObj[key] = 0;
77716
+ } else if (value.type === "string") {
77717
+ exampleObj[key] = value.description || "your answer here";
77718
+ } else if (value.type === "array") {
77719
+ exampleObj[key] = [];
77720
+ } else {
77721
+ exampleObj[key] = {};
77722
+ }
77723
+ }
77724
+ return exampleObj;
77725
+ } catch (e3) {
77726
+ if (debug) {
77727
+ console.error("[DEBUG] generateExampleFromSchema: Failed to parse schema:", e3.message);
77728
+ }
77729
+ return null;
77730
+ }
77731
+ }
77732
+ function generateSchemaInstructions(schema, options = {}) {
77733
+ const { debug = false } = options;
77734
+ let instructions = "\n\nIMPORTANT: When you provide your final answer using attempt_completion, you MUST format it as valid JSON matching this schema:\n\n";
77735
+ try {
77736
+ const parsedSchema = typeof schema === "string" ? JSON.parse(schema) : schema;
77737
+ instructions += `${JSON.stringify(parsedSchema, null, 2)}
77738
+
77739
+ `;
77740
+ } catch (e3) {
77741
+ if (debug) {
77742
+ console.error("[DEBUG] generateSchemaInstructions: Failed to parse schema:", e3.message);
77743
+ }
77744
+ instructions += `${schema}
77745
+
77746
+ `;
77747
+ }
77748
+ instructions += "Your response inside attempt_completion must be ONLY valid JSON - no plain text, no explanations, no markdown.\n\nIMPORTANT: First complete the requested analysis/task thoroughly, then provide your final answer in the JSON format above.";
77749
+ return instructions;
77750
+ }
77701
77751
  function enforceNoAdditionalProperties(schema) {
77702
77752
  if (!schema || typeof schema !== "object") {
77703
77753
  return schema;
@@ -81727,9 +81777,14 @@ You are working with a repository located at: ${searchDirectory}
81727
81777
  });
81728
81778
  const systemMessage = await this.getSystemMessage();
81729
81779
  let userMessage = { role: "user", content: message.trim() };
81780
+ if (options.schema && !options._schemaFormatted) {
81781
+ const schemaInstructions = generateSchemaInstructions(options.schema, { debug: this.debug });
81782
+ userMessage.content = message.trim() + schemaInstructions;
81783
+ }
81730
81784
  if (images && images.length > 0) {
81785
+ const textContent = userMessage.content;
81731
81786
  userMessage.content = [
81732
- { type: "text", text: message.trim() },
81787
+ { type: "text", text: textContent },
81733
81788
  ...images.map((image) => ({
81734
81789
  type: "image",
81735
81790
  image
@@ -82149,26 +82204,7 @@ Error: Unknown tool '${toolName}'. Available tools: ${allAvailableTools.join(",
82149
82204
  break;
82150
82205
  }
82151
82206
  currentMessages.push({ role: "assistant", content: assistantResponseContent });
82152
- let reminderContent;
82153
- if (options.schema) {
82154
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
82155
-
82156
- Remember: Use proper XML format with BOTH opening and closing tags:
82157
-
82158
- <tool_name>
82159
- <parameter>value</parameter>
82160
- </tool_name>
82161
-
82162
- IMPORTANT: A schema was provided for the final output format.
82163
-
82164
- You MUST use attempt_completion to provide your answer:
82165
- <attempt_completion>
82166
- [Your complete answer here - provide in natural language, it will be automatically formatted to match the schema]
82167
- </attempt_completion>
82168
-
82169
- Your response will be automatically formatted to JSON. You can provide your answer in natural language or as JSON - either will work.`;
82170
- } else {
82171
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
82207
+ const reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
82172
82208
 
82173
82209
  Remember: Use proper XML format with BOTH opening and closing tags:
82174
82210
 
@@ -82180,7 +82216,6 @@ Or for quick completion if your previous response was already correct and comple
82180
82216
  <attempt_complete>
82181
82217
 
82182
82218
  IMPORTANT: When using <attempt_complete>, this must be the ONLY content in your response. No additional text, explanations, or other content should be included. This tag signals to reuse your previous response as the final answer.`;
82183
- }
82184
82219
  currentMessages.push({
82185
82220
  role: "user",
82186
82221
  content: reminderContent
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probelabs/probe",
3
- "version": "0.6.0-rc162",
3
+ "version": "0.6.0-rc164",
4
4
  "description": "Node.js wrapper for the probe code search tool",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -48,6 +48,7 @@ import {
48
48
  isJsonSchema,
49
49
  validateJsonResponse,
50
50
  createJsonCorrectionPrompt,
51
+ generateSchemaInstructions,
51
52
  isJsonSchemaDefinition,
52
53
  createSchemaDefinitionCorrectionPrompt,
53
54
  validateAndFixMermaidResponse
@@ -1455,11 +1456,18 @@ When troubleshooting:
1455
1456
 
1456
1457
  // Create user message with optional image support
1457
1458
  let userMessage = { role: 'user', content: message.trim() };
1458
-
1459
+
1460
+ // If schema is provided, prepend JSON format requirement to user message
1461
+ if (options.schema && !options._schemaFormatted) {
1462
+ const schemaInstructions = generateSchemaInstructions(options.schema, { debug: this.debug });
1463
+ userMessage.content = message.trim() + schemaInstructions;
1464
+ }
1465
+
1459
1466
  // If images are provided, use multi-modal message format
1460
1467
  if (images && images.length > 0) {
1468
+ const textContent = userMessage.content;
1461
1469
  userMessage.content = [
1462
- { type: 'text', text: message.trim() },
1470
+ { type: 'text', text: textContent },
1463
1471
  ...images.map(image => ({
1464
1472
  type: 'image',
1465
1473
  image: image
@@ -2001,29 +2009,8 @@ When troubleshooting:
2001
2009
  // Add assistant response and ask for tool usage
2002
2010
  currentMessages.push({ role: 'assistant', content: assistantResponseContent });
2003
2011
 
2004
- // Build appropriate reminder message based on whether schema is provided
2005
- let reminderContent;
2006
- if (options.schema) { // Apply for ANY schema, not just JSON schemas
2007
- // When schema is provided, AI must use attempt_completion to trigger schema formatting
2008
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
2009
-
2010
- Remember: Use proper XML format with BOTH opening and closing tags:
2011
-
2012
- <tool_name>
2013
- <parameter>value</parameter>
2014
- </tool_name>
2015
-
2016
- IMPORTANT: A schema was provided for the final output format.
2017
-
2018
- You MUST use attempt_completion to provide your answer:
2019
- <attempt_completion>
2020
- [Your complete answer here - provide in natural language, it will be automatically formatted to match the schema]
2021
- </attempt_completion>
2022
-
2023
- Your response will be automatically formatted to JSON. You can provide your answer in natural language or as JSON - either will work.`;
2024
- } else {
2025
- // Standard reminder without schema
2026
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
2012
+ // Standard reminder - schema was already provided in initial message
2013
+ const reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
2027
2014
 
2028
2015
  Remember: Use proper XML format with BOTH opening and closing tags:
2029
2016
 
@@ -2035,7 +2022,6 @@ Or for quick completion if your previous response was already correct and comple
2035
2022
  <attempt_complete>
2036
2023
 
2037
2024
  IMPORTANT: When using <attempt_complete>, this must be the ONLY content in your response. No additional text, explanations, or other content should be included. This tag signals to reuse your previous response as the final answer.`;
2038
- }
2039
2025
 
2040
2026
  currentMessages.push({
2041
2027
  role: 'user',
@@ -7,6 +7,74 @@ import { createMessagePreview } from '../tools/common.js';
7
7
  import { validate, fixText, extractMermaidBlocks } from '@probelabs/maid';
8
8
  import Ajv from 'ajv';
9
9
 
10
+ /**
11
+ * Generate an example JSON object from a JSON schema
12
+ * @param {Object|string} schema - JSON schema object or string
13
+ * @param {Object} options - Options for generation
14
+ * @param {boolean} [options.debug=false] - Enable debug logging
15
+ * @returns {Object|null} - Example object, or null if schema cannot be processed
16
+ */
17
+ export function generateExampleFromSchema(schema, options = {}) {
18
+ const { debug = false } = options;
19
+
20
+ try {
21
+ const parsedSchema = typeof schema === 'string' ? JSON.parse(schema) : schema;
22
+
23
+ if (parsedSchema.type !== 'object' || !parsedSchema.properties) {
24
+ return null;
25
+ }
26
+
27
+ const exampleObj = {};
28
+ for (const [key, value] of Object.entries(parsedSchema.properties)) {
29
+ if (value.type === 'boolean') {
30
+ exampleObj[key] = false;
31
+ } else if (value.type === 'number') {
32
+ exampleObj[key] = 0;
33
+ } else if (value.type === 'string') {
34
+ exampleObj[key] = value.description || 'your answer here';
35
+ } else if (value.type === 'array') {
36
+ exampleObj[key] = [];
37
+ } else {
38
+ exampleObj[key] = {};
39
+ }
40
+ }
41
+
42
+ return exampleObj;
43
+ } catch (e) {
44
+ if (debug) {
45
+ console.error('[DEBUG] generateExampleFromSchema: Failed to parse schema:', e.message);
46
+ }
47
+ return null;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Generate schema instructions for AI to follow
53
+ * @param {Object|string} schema - JSON schema object or string
54
+ * @param {Object} options - Options for generation
55
+ * @param {boolean} [options.debug=false] - Enable debug logging
56
+ * @returns {string} - Formatted schema instructions
57
+ */
58
+ export function generateSchemaInstructions(schema, options = {}) {
59
+ const { debug = false } = options;
60
+
61
+ let instructions = '\n\nIMPORTANT: When you provide your final answer using attempt_completion, you MUST format it as valid JSON matching this schema:\n\n';
62
+
63
+ try {
64
+ const parsedSchema = typeof schema === 'string' ? JSON.parse(schema) : schema;
65
+ instructions += `${JSON.stringify(parsedSchema, null, 2)}\n\n`;
66
+ } catch (e) {
67
+ if (debug) {
68
+ console.error('[DEBUG] generateSchemaInstructions: Failed to parse schema:', e.message);
69
+ }
70
+ instructions += `${schema}\n\n`;
71
+ }
72
+
73
+ instructions += 'Your response inside attempt_completion must be ONLY valid JSON - no plain text, no explanations, no markdown.\n\nIMPORTANT: First complete the requested analysis/task thoroughly, then provide your final answer in the JSON format above.';
74
+
75
+ return instructions;
76
+ }
77
+
10
78
  /**
11
79
  * Recursively apply additionalProperties: false to all object schemas
12
80
  * This ensures strict validation at all nesting levels