@exreve/exk 1.0.48 → 1.0.49

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.
@@ -960,10 +960,14 @@ export class AgentSessionManager {
960
960
  }
961
961
  else if (message.type === 'user') {
962
962
  const msg = message;
963
- // SDK 0.2.x: tool results appear in message.content as tool_result blocks.
964
- // The tool_use_id is ALWAYS in message.content[].tool_use_id never in
965
- // the top-level tool_use_result field. We must extract it from message.content
966
- // first, then use either parsed content blocks or tool_use_result as the data source.
963
+ // SDK sends tool results with TWO data sources:
964
+ // message.content[0] — {type:'tool_result', tool_use_id:'...', content: <raw text>}
965
+ // msg.tool_use_result structured object with {stdout,stderr} for Bash,
966
+ // {type,file} for Read, or [{type:'text',text:'...'}] for MCP tools
967
+ //
968
+ // The tool_use_id lives ONLY in message.content[].tool_use_id.
969
+ // The structured result lives in tool_use_result for built-in tools.
970
+ // For MCP tools, tool_use_result is a content-block array we need to parse.
967
971
  let toolResult = null;
968
972
  let toolUseId = msg.parent_tool_use_id;
969
973
  // STEP 1: Always extract tool_use_id from message.content (authoritative source)
@@ -974,8 +978,41 @@ export class AgentSessionManager {
974
978
  toolUseId = toolResultBlock.tool_use_id;
975
979
  }
976
980
  }
977
- // STEP 2: Try to parse the actual result from message.content tool_result block
978
- if (Array.isArray(msg.message?.content)) {
981
+ // STEP 2: Use tool_use_result as the primary data source.
982
+ // For built-in tools (Bash, Read, Edit, Write, Glob, Grep) it's a structured
983
+ // object like {stdout, stderr} or {type:'text', file:{...}} — use directly.
984
+ // For MCP tools it's a content-block array [{type:'text', text:'...'}] — parse text.
985
+ if (msg.tool_use_result) {
986
+ const raw = msg.tool_use_result;
987
+ if (Array.isArray(raw)) {
988
+ // MCP tool result: [{type:'text', text:'...'}] — extract and parse
989
+ const textParts = raw
990
+ .filter((c) => c.type === 'text')
991
+ .map((c) => c.text);
992
+ const rawContent = textParts.join('\n');
993
+ try {
994
+ toolResult = JSON.parse(rawContent);
995
+ }
996
+ catch {
997
+ toolResult = { content: rawContent, type: 'text' };
998
+ }
999
+ }
1000
+ else if (typeof raw === 'object' && raw !== null) {
1001
+ // Built-in tool result: {stdout, stderr, ...} or {type, file, ...} — use directly
1002
+ toolResult = raw;
1003
+ }
1004
+ else if (typeof raw === 'string') {
1005
+ try {
1006
+ toolResult = JSON.parse(raw);
1007
+ }
1008
+ catch {
1009
+ toolResult = { content: raw, type: 'text' };
1010
+ }
1011
+ }
1012
+ }
1013
+ // STEP 3: Fallback to parsing message.content if tool_use_result wasn't available
1014
+ // (e.g. subagent calls where tool_use_result may be absent)
1015
+ if (!toolResult && Array.isArray(msg.message?.content)) {
979
1016
  const contentBlocks = msg.message.content;
980
1017
  const toolResultBlock = contentBlocks.find((c) => c.type === 'tool_result');
981
1018
  if (toolResultBlock) {
@@ -988,7 +1025,6 @@ export class AgentSessionManager {
988
1025
  }
989
1026
  }
990
1027
  else if (Array.isArray(toolResultBlock.content)) {
991
- // Extract text from content blocks and try to parse as JSON
992
1028
  const textParts = toolResultBlock.content
993
1029
  .filter((c) => c.type === 'text')
994
1030
  .map((c) => c.text);
@@ -1005,35 +1041,6 @@ export class AgentSessionManager {
1005
1041
  }
1006
1042
  }
1007
1043
  }
1008
- // STEP 3: Fallback to top-level tool_use_result if message.content didn't yield a result
1009
- // (present in SDK 0.1.x and some 0.2.x messages). Parse the raw content blocks.
1010
- if (!toolResult && msg.tool_use_result) {
1011
- const raw = msg.tool_use_result;
1012
- if (Array.isArray(raw)) {
1013
- // tool_use_result is [{type:"text", text:"..."}] — extract and parse text
1014
- const textParts = raw
1015
- .filter((c) => c.type === 'text')
1016
- .map((c) => c.text);
1017
- const rawContent = textParts.join('\n');
1018
- try {
1019
- toolResult = JSON.parse(rawContent);
1020
- }
1021
- catch {
1022
- toolResult = { content: rawContent, type: 'text' };
1023
- }
1024
- }
1025
- else if (typeof raw === 'string') {
1026
- try {
1027
- toolResult = JSON.parse(raw);
1028
- }
1029
- catch {
1030
- toolResult = { content: raw, type: 'text' };
1031
- }
1032
- }
1033
- else {
1034
- toolResult = raw;
1035
- }
1036
- }
1037
1044
  if (toolResult) {
1038
1045
  const detectedName = extractToolName(toolResult);
1039
1046
  const resolvedName = detectedName !== 'unknown'
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exreve/exk",
3
- "version": "1.0.48",
3
+ "version": "1.0.49",
4
4
  "description": "exk - Control Claude CLI with voice and programmable interfaces",
5
5
  "type": "module",
6
6
  "bin": {