@mcpc-tech/core 0.2.5 → 0.2.7-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.mjs +76 -35
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -685,9 +685,42 @@ function stripMarkdownAndText(text) {
685
685
  text = text.replace(/^```(?:json)?\s*\n?/i, "");
686
686
  text = text.replace(/\n?```\s*$/, "");
687
687
  text = text.replace(/^(?:here is|here's|response|result|output|json):\s*/i, "");
688
- const jsonMatch = text.match(/(\{[\s\S]*\}|\[[\s\S]*\])/);
689
- if (jsonMatch) {
690
- text = jsonMatch[1];
688
+ const firstJsonIndex = text.search(/[\{\[]/);
689
+ if (firstJsonIndex >= 0) {
690
+ text = text.slice(firstJsonIndex);
691
+ let depth = 0;
692
+ let inString = false;
693
+ let escapeNext = false;
694
+ const startChar = text[0];
695
+ const endChar = startChar === "{" ? "}" : "]";
696
+ for (let i = 0; i < text.length; i++) {
697
+ const char = text[i];
698
+ if (escapeNext) {
699
+ escapeNext = false;
700
+ continue;
701
+ }
702
+ if (char === "\\") {
703
+ escapeNext = true;
704
+ continue;
705
+ }
706
+ if (char === '"' && !inString) {
707
+ inString = true;
708
+ continue;
709
+ }
710
+ if (char === '"' && inString) {
711
+ inString = false;
712
+ continue;
713
+ }
714
+ if (inString) continue;
715
+ if (char === startChar) {
716
+ depth++;
717
+ } else if (char === endChar) {
718
+ depth--;
719
+ if (depth === 0) {
720
+ return text.slice(0, i + 1);
721
+ }
722
+ }
723
+ }
691
724
  }
692
725
  return text.trim();
693
726
  }
@@ -1464,13 +1497,13 @@ var AgenticExecutor = class {
1464
1497
  this.tracingEnabled = false;
1465
1498
  }
1466
1499
  }
1467
- async execute(args, schema) {
1500
+ async execute(args, schema, parentSpan) {
1468
1501
  const executeSpan = this.tracingEnabled ? startSpan("mcpc.agentic_execute", {
1469
1502
  agent: this.name,
1470
1503
  action: String(args[this.ACTION_KEY] ?? "unknown"),
1471
1504
  nextAction: String(args[this.NEXT_ACTION_KEY] ?? "none"),
1472
1505
  args: JSON.stringify(args)
1473
- }) : null;
1506
+ }, parentSpan ?? void 0) : null;
1474
1507
  try {
1475
1508
  const validationResult = this.validate(args, schema);
1476
1509
  if (!validationResult.valid) {
@@ -2064,7 +2097,7 @@ var BaseSamplingExecutor = class {
2064
2097
  role: "user",
2065
2098
  content: {
2066
2099
  type: "text",
2067
- text: 'Return ONLY raw JSON (no code fences or explanations). The JSON MUST include action and decision. Example: {"action":"<tool>","decision":"proceed|complete","<tool>":{}}'
2100
+ text: 'Return ONE AND ONLY ONE raw JSON object (no code fences, explanations, or multiple objects). The JSON MUST include action and decision. Example: {"action":"<tool>","decision":"proceed|complete","<tool>":{}}'
2068
2101
  }
2069
2102
  }
2070
2103
  ];
@@ -2100,15 +2133,13 @@ var BaseSamplingExecutor = class {
2100
2133
  if (iterationSpan) endSpan(iterationSpan);
2101
2134
  continue;
2102
2135
  }
2103
- if (parsedData) {
2104
- this.conversationHistory.push({
2105
- role: "assistant",
2106
- content: {
2107
- type: "text",
2108
- text: JSON.stringify(parsedData, null, 2)
2109
- }
2110
- });
2111
- }
2136
+ this.conversationHistory.push({
2137
+ role: "assistant",
2138
+ content: {
2139
+ type: "text",
2140
+ text: JSON.stringify(parsedData, null, 2)
2141
+ }
2142
+ });
2112
2143
  const action = parsedData["action"];
2113
2144
  const actionStr = action && typeof action === "string" ? String(action) : "unknown_action";
2114
2145
  const spanName = `mcpc.sampling_iteration.${actionStr}`;
@@ -2132,7 +2163,7 @@ var BaseSamplingExecutor = class {
2132
2163
  if (iterationSpan) endSpan(iterationSpan);
2133
2164
  continue;
2134
2165
  }
2135
- const result = await this.processAction(parsedData, schema, state, loopSpan);
2166
+ const result = await this.processAction(parsedData, schema, state, iterationSpan);
2136
2167
  this.logIterationProgress(parsedData, result, model, stopReason, role);
2137
2168
  if (iterationSpan) {
2138
2169
  let rawJson = "{}";
@@ -2186,23 +2217,15 @@ var BaseSamplingExecutor = class {
2186
2217
  return await this.createExecutionError(error, loopSpan);
2187
2218
  }
2188
2219
  }
2189
- addParsingErrorToHistory(responseText, parseError) {
2190
- this.conversationHistory.push({
2191
- role: "assistant",
2192
- content: {
2193
- type: "text",
2194
- text: `JSON parsing failed. Response was: ${responseText}`
2195
- }
2196
- });
2220
+ addParsingErrorToHistory(_responseText, parseError) {
2221
+ const errorMsg = parseError instanceof Error ? parseError.message : String(parseError);
2197
2222
  this.conversationHistory.push({
2198
2223
  role: "user",
2199
2224
  content: {
2200
2225
  type: "text",
2201
- text: CompiledPrompts.errorResponse({
2202
- errorMessage: `JSON parsing failed: ${parseError instanceof Error ? parseError.message : String(parseError)}
2226
+ text: `Invalid JSON: ${errorMsg}
2203
2227
 
2204
- Please respond with valid JSON.`
2205
- })
2228
+ Respond with valid JSON.`
2206
2229
  }
2207
2230
  });
2208
2231
  }
@@ -2340,11 +2363,11 @@ ${msg.content.text}`;
2340
2363
  });
2341
2364
  }
2342
2365
  injectJsonInstruction({ prompt, schema, schemaPrefix = "JSON schema:", schemaSuffix = `STRICT REQUIREMENTS:
2343
- 1. Return ONLY raw JSON that passes JSON.parse() - no markdown, code blocks, explanatory text, or extra characters
2366
+ 1. Return ONE AND ONLY ONE raw JSON object that passes JSON.parse() - no markdown, code blocks, explanatory text, or multiple JSON objects
2344
2367
  2. Include ALL required fields with correct data types and satisfy ALL schema constraints (anyOf, oneOf, allOf, not, enum, pattern, min/max, conditionals)
2345
- 3. Your response must be the JSON object itself, nothing else
2368
+ 3. Your response must be a single JSON object, nothing else
2346
2369
 
2347
- INVALID: \`\`\`json{"key":"value"}\`\`\` or "Here is: {"key":"value"}"
2370
+ INVALID: \`\`\`json{"key":"value"}\`\`\` or "Here is: {"key":"value"}" or {"key":"value"}{"key":"value"}
2348
2371
  VALID: {"key":"value"}` }) {
2349
2372
  return [
2350
2373
  prompt != null && prompt.length > 0 ? prompt : void 0,
@@ -2420,12 +2443,21 @@ var SamplingExecutor = class extends BaseSamplingExecutor {
2420
2443
  }
2421
2444
  async processAction(parsedData, schema, _state, parentSpan) {
2422
2445
  const toolCallData = parsedData;
2446
+ const isComplete = toolCallData.decision === "complete";
2447
+ const actionName = toolCallData.action;
2448
+ if (isComplete && actionName && actionName !== "complete") {
2449
+ this.logger.debug({
2450
+ message: "Decision is 'complete' with action present, treating as 'proceed'",
2451
+ action: actionName
2452
+ });
2453
+ toolCallData.decision = "proceed";
2454
+ }
2423
2455
  if (toolCallData.decision === "complete") {
2424
2456
  return await this.createCompletionResult("Task completed", parentSpan);
2425
2457
  }
2426
2458
  try {
2427
2459
  const { action: _action, decision: _decision, ..._toolArgs } = toolCallData;
2428
- const toolResult = await this.agenticExecutor.execute(toolCallData, schema);
2460
+ const toolResult = await this.agenticExecutor.execute(toolCallData, schema, parentSpan);
2429
2461
  const resultText = toolResult.content?.filter((content) => content.type === "text")?.map((content) => content.text)?.join("\n") || "No result";
2430
2462
  this.conversationHistory.push({
2431
2463
  role: "assistant",
@@ -2465,10 +2497,10 @@ ${JSON.stringify(context2, null, 2)}`;
2465
2497
  const taskPrompt = `
2466
2498
 
2467
2499
  ## Current Task
2468
- I will now use agentic sampling to complete the following task: "${userRequest}"${contextInfo}
2500
+ You will now use agentic sampling to complete the following task: "${userRequest}"${contextInfo}
2469
2501
 
2470
- When I need to use a tool, I should specify the tool name in 'action' and provide tool-specific parameters as additional properties.
2471
- When the task is complete, I should use "action": "complete".`;
2502
+ When you need to use a tool, specify the tool name in 'action' and provide tool-specific parameters as additional properties.
2503
+ When the task is complete, use "action": "complete".`;
2472
2504
  return this.injectJsonInstruction({
2473
2505
  prompt: basePrompt + taskPrompt,
2474
2506
  schema: agenticSchema
@@ -3040,6 +3072,15 @@ var WorkflowSamplingExecutor = class extends BaseSamplingExecutor {
3040
3072
  throw new Error("WorkflowState is required for workflow");
3041
3073
  }
3042
3074
  const toolCallData = parsedData;
3075
+ const isComplete = toolCallData.decision === "complete";
3076
+ const actionName = toolCallData.action;
3077
+ if (isComplete && actionName && actionName !== "complete") {
3078
+ this.logger.debug({
3079
+ message: "Decision is 'complete' with action present, treating as 'proceed'",
3080
+ action: actionName
3081
+ });
3082
+ toolCallData.decision = "proceed";
3083
+ }
3043
3084
  if (toolCallData.decision === "complete") {
3044
3085
  return await this.createCompletionResult("Task completed", parentSpan);
3045
3086
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcpc-tech/core",
3
- "version": "0.2.5",
3
+ "version": "0.2.7-beta.1",
4
4
  "homepage": "https://jsr.io/@mcpc/core",
5
5
  "type": "module",
6
6
  "dependencies": {