@emseepea/testing 0.26.14 → 0.26.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emseepea/testing",
3
- "version": "0.26.14",
3
+ "version": "0.26.15",
4
4
  "description": "MCP integration and semantic testing helpers",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -57,7 +57,7 @@
57
57
  "test:llm:built": "emseepea-test eval"
58
58
  },
59
59
  "dependencies": {
60
- "@emseepea/server": "0.25.10",
60
+ "@emseepea/server": "0.26.0",
61
61
  "@modelcontextprotocol/client": "2.3.1",
62
62
  "@modelcontextprotocol/server": "2.3.1",
63
63
  "@modelcontextprotocol/core": "2.3.1"
@@ -454,9 +454,6 @@ export function parseCodexEvents(stdout, advertisedTools, expectedThreadId, proc
454
454
  if (authentication.test(errorText)) {
455
455
  throw codexEvidenceError("Model command is not signed in", "authentication");
456
456
  }
457
- const failedTool = events.some(({ item }) => item?.type === "mcp_tool_call"
458
- && (item.status === "failed" || item.result?.isError === true || item.result?.is_error === true));
459
- if (failedTool) throw new Error("Model command reported a failed MCP tool call");
460
457
  if (processExitCode !== 0) throw codexProcessError(processExitCode, providerFailureCategory);
461
458
  if (events.some(({ type }) => type === "turn.failed" || type === "error")) {
462
459
  throw new Error("Model command reported an error");
@@ -479,6 +476,20 @@ export function parseCodexEvents(stdout, advertisedTools, expectedThreadId, proc
479
476
  const forbidden = completed.filter((item) => !["agent_message", "reasoning", "mcp_tool_call"].includes(item?.type));
480
477
  if (forbidden.length) throw forbiddenItemError(forbidden);
481
478
  const toolItems = completed.filter(({ type }) => type === "mcp_tool_call");
479
+ const terminalAnswerIndex = completed.findLastIndex(({ type }) => type === "agent_message");
480
+ const codexApplicationError = (item) => item.status === "failed"
481
+ && item.server === mcpServerName && advertised.has(item.tool)
482
+ && item.arguments && typeof item.arguments === "object" && !Array.isArray(item.arguments)
483
+ && item.result && typeof item.result === "object" && !Array.isArray(item.result)
484
+ && Object.keys(item.result).sort().join(",") === "content,structured_content"
485
+ && item.result.structured_content === null
486
+ && Array.isArray(item.result.content) && item.result.content.length > 0
487
+ && item.result.content.every((block) => block && block.type === "text"
488
+ && typeof block.text === "string" && block.text.length > 0)
489
+ && completed.indexOf(item) < terminalAnswerIndex;
490
+ if (toolItems.some((item) => item.status === "failed" && !codexApplicationError(item))) {
491
+ throw new Error("Model command reported a failed MCP tool call");
492
+ }
482
493
  const resourceItems = resourceCatalogue ? toolItems.flatMap((item) => {
483
494
  const operation = resourceHelperOperation(item, resourceCatalogue);
484
495
  return operation ? [{ item, operation }] : [];
@@ -495,8 +506,10 @@ export function parseCodexEvents(stdout, advertisedTools, expectedThreadId, proc
495
506
  || !item.arguments || typeof item.arguments !== "object" || Array.isArray(item.arguments)) {
496
507
  throw forbiddenItemError([item]);
497
508
  }
498
- if (!item.result || typeof item.result !== "object" || item.status === "failed"
499
- || item.result.isError === true || item.result.is_error === true) {
509
+ const applicationError = codexApplicationError(item)
510
+ || item.result?.isError === true || item.result?.is_error === true;
511
+ if (!item.result || typeof item.result !== "object"
512
+ || (item.status !== "completed" && !(item.status === "failed" && applicationError))) {
500
513
  throw new Error("Model command reported a failed MCP tool call");
501
514
  }
502
515
  return { name: item.tool, arguments: item.arguments };
@@ -504,7 +517,11 @@ export function parseCodexEvents(stdout, advertisedTools, expectedThreadId, proc
504
517
  const messages = completed.filter(({ type }) => type === "agent_message");
505
518
  const answer = messages.at(-1)?.text;
506
519
  if (typeof answer !== "string") throw new Error("Model command returned no answer");
507
- const toolResults = applicationToolItems.map(({ result }) => ({ content: result.content ?? result, isError: false }));
520
+ const toolResults = applicationToolItems.map((item) => ({
521
+ content: item.result.content ?? item.result,
522
+ isError: item.result.isError === true || item.result.is_error === true
523
+ || codexApplicationError(item),
524
+ }));
508
525
  return {
509
526
  answer,
510
527
  calls,