@emblemvault/hustle-react 1.4.2 → 1.4.3

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.
@@ -15178,7 +15178,14 @@ function HustleChat({
15178
15178
  setIsStreaming(true);
15179
15179
  setCurrentToolCalls([]);
15180
15180
  try {
15181
- const chatMessages = messagesRef.current.filter((m2) => !m2.isStreaming).map((m2) => ({ role: m2.role, content: m2.content }));
15181
+ const chatMessages = messagesRef.current.filter((m2) => !m2.isStreaming).map((m2) => {
15182
+ const msg = { role: m2.role, content: m2.content };
15183
+ if (m2.role === "assistant" && m2.toolInvocations && m2.toolInvocations.length > 0) {
15184
+ msg.toolInvocations = m2.toolInvocations;
15185
+ msg.parts = m2.parts;
15186
+ }
15187
+ return msg;
15188
+ });
15182
15189
  chatMessages.push({ role: "user", content: "continue" });
15183
15190
  const stream = chatStream({
15184
15191
  messages: chatMessages,
@@ -15186,6 +15193,9 @@ function HustleChat({
15186
15193
  });
15187
15194
  let fullContent = "";
15188
15195
  const toolCallsAccumulated = [];
15196
+ const toolInvocationsAccumulated = [];
15197
+ const partsAccumulated = [{ type: "step-start" }];
15198
+ let stepCounter = 0;
15189
15199
  for await (const chunk of stream) {
15190
15200
  if (chunk.type === "text") {
15191
15201
  fullContent += chunk.value;
@@ -15197,22 +15207,79 @@ function HustleChat({
15197
15207
  } else if (chunk.type === "tool_call") {
15198
15208
  const toolCall = chunk.value;
15199
15209
  toolCallsAccumulated.push(toolCall);
15210
+ const invocation = {
15211
+ state: "call",
15212
+ step: stepCounter++,
15213
+ toolCallId: toolCall.toolCallId,
15214
+ toolName: toolCall.toolName,
15215
+ args: toolCall.args
15216
+ };
15217
+ toolInvocationsAccumulated.push(invocation);
15218
+ partsAccumulated.push({ type: "tool-invocation", toolInvocation: invocation });
15200
15219
  setCurrentToolCalls([...toolCallsAccumulated]);
15201
15220
  setMessages(
15202
15221
  (prev) => prev.map(
15203
- (m2) => m2.id === assistantMessage.id ? { ...m2, toolCalls: [...toolCallsAccumulated] } : m2
15222
+ (m2) => m2.id === assistantMessage.id ? {
15223
+ ...m2,
15224
+ toolCalls: [...toolCallsAccumulated],
15225
+ toolInvocations: [...toolInvocationsAccumulated],
15226
+ parts: [...partsAccumulated]
15227
+ } : m2
15204
15228
  )
15205
15229
  );
15206
15230
  onToolCall?.(toolCall);
15231
+ } else if (chunk.type === "tool_result") {
15232
+ const toolResult = chunk.value;
15233
+ const invocationIndex = toolInvocationsAccumulated.findIndex(
15234
+ (inv) => inv.toolCallId === toolResult.toolCallId
15235
+ );
15236
+ if (invocationIndex !== -1) {
15237
+ toolInvocationsAccumulated[invocationIndex] = {
15238
+ ...toolInvocationsAccumulated[invocationIndex],
15239
+ state: "result",
15240
+ result: toolResult.result
15241
+ };
15242
+ const partIndex = partsAccumulated.findIndex(
15243
+ (p) => p.type === "tool-invocation" && p.toolInvocation.toolCallId === toolResult.toolCallId
15244
+ );
15245
+ if (partIndex !== -1) {
15246
+ partsAccumulated[partIndex] = {
15247
+ type: "tool-invocation",
15248
+ toolInvocation: toolInvocationsAccumulated[invocationIndex]
15249
+ };
15250
+ }
15251
+ }
15252
+ setMessages(
15253
+ (prev) => prev.map(
15254
+ (m2) => m2.id === assistantMessage.id ? {
15255
+ ...m2,
15256
+ toolInvocations: [...toolInvocationsAccumulated],
15257
+ parts: [...partsAccumulated]
15258
+ } : m2
15259
+ )
15260
+ );
15207
15261
  } else if (chunk.type === "error") {
15208
15262
  console.error("Stream error:", chunk.value);
15209
15263
  }
15210
15264
  }
15211
15265
  const processedResponse = await stream.response;
15212
15266
  const finalContent = processedResponse?.content || fullContent || "(No response)";
15267
+ const finalParts = [{ type: "step-start" }];
15268
+ if (finalContent) {
15269
+ finalParts.push({ type: "text", text: finalContent });
15270
+ }
15271
+ for (const inv of toolInvocationsAccumulated) {
15272
+ finalParts.push({ type: "tool-invocation", toolInvocation: inv });
15273
+ }
15213
15274
  setMessages(
15214
15275
  (prev) => prev.map(
15215
- (m2) => m2.id === assistantMessage.id ? { ...m2, isStreaming: false, content: finalContent } : m2
15276
+ (m2) => m2.id === assistantMessage.id ? {
15277
+ ...m2,
15278
+ isStreaming: false,
15279
+ content: finalContent,
15280
+ toolInvocations: toolInvocationsAccumulated.length > 0 ? toolInvocationsAccumulated : void 0,
15281
+ parts: toolInvocationsAccumulated.length > 0 ? finalParts : void 0
15282
+ } : m2
15216
15283
  )
15217
15284
  );
15218
15285
  onResponse?.(finalContent);
@@ -15274,7 +15341,14 @@ function HustleChat({
15274
15341
  setIsStreaming(true);
15275
15342
  setCurrentToolCalls([]);
15276
15343
  try {
15277
- const chatMessages = messages.filter((m2) => !m2.isStreaming).map((m2) => ({ role: m2.role, content: m2.content }));
15344
+ const chatMessages = messages.filter((m2) => !m2.isStreaming).map((m2) => {
15345
+ const msg = { role: m2.role, content: m2.content };
15346
+ if (m2.role === "assistant" && m2.toolInvocations && m2.toolInvocations.length > 0) {
15347
+ msg.toolInvocations = m2.toolInvocations;
15348
+ msg.parts = m2.parts;
15349
+ }
15350
+ return msg;
15351
+ });
15278
15352
  chatMessages.push({ role: "user", content });
15279
15353
  const stream = chatStream({
15280
15354
  messages: chatMessages,
@@ -15284,6 +15358,9 @@ function HustleChat({
15284
15358
  setAttachments([]);
15285
15359
  let fullContent = "";
15286
15360
  const toolCallsAccumulated = [];
15361
+ const toolInvocationsAccumulated = [];
15362
+ const partsAccumulated = [{ type: "step-start" }];
15363
+ let stepCounter = 0;
15287
15364
  for await (const chunk of stream) {
15288
15365
  if (chunk.type === "text") {
15289
15366
  fullContent += chunk.value;
@@ -15295,22 +15372,79 @@ function HustleChat({
15295
15372
  } else if (chunk.type === "tool_call") {
15296
15373
  const toolCall = chunk.value;
15297
15374
  toolCallsAccumulated.push(toolCall);
15375
+ const invocation = {
15376
+ state: "call",
15377
+ step: stepCounter++,
15378
+ toolCallId: toolCall.toolCallId,
15379
+ toolName: toolCall.toolName,
15380
+ args: toolCall.args
15381
+ };
15382
+ toolInvocationsAccumulated.push(invocation);
15383
+ partsAccumulated.push({ type: "tool-invocation", toolInvocation: invocation });
15298
15384
  setCurrentToolCalls([...toolCallsAccumulated]);
15299
15385
  setMessages(
15300
15386
  (prev) => prev.map(
15301
- (m2) => m2.id === assistantMessage.id ? { ...m2, toolCalls: [...toolCallsAccumulated] } : m2
15387
+ (m2) => m2.id === assistantMessage.id ? {
15388
+ ...m2,
15389
+ toolCalls: [...toolCallsAccumulated],
15390
+ toolInvocations: [...toolInvocationsAccumulated],
15391
+ parts: [...partsAccumulated]
15392
+ } : m2
15302
15393
  )
15303
15394
  );
15304
15395
  onToolCall?.(toolCall);
15396
+ } else if (chunk.type === "tool_result") {
15397
+ const toolResult = chunk.value;
15398
+ const invocationIndex = toolInvocationsAccumulated.findIndex(
15399
+ (inv) => inv.toolCallId === toolResult.toolCallId
15400
+ );
15401
+ if (invocationIndex !== -1) {
15402
+ toolInvocationsAccumulated[invocationIndex] = {
15403
+ ...toolInvocationsAccumulated[invocationIndex],
15404
+ state: "result",
15405
+ result: toolResult.result
15406
+ };
15407
+ const partIndex = partsAccumulated.findIndex(
15408
+ (p) => p.type === "tool-invocation" && p.toolInvocation.toolCallId === toolResult.toolCallId
15409
+ );
15410
+ if (partIndex !== -1) {
15411
+ partsAccumulated[partIndex] = {
15412
+ type: "tool-invocation",
15413
+ toolInvocation: toolInvocationsAccumulated[invocationIndex]
15414
+ };
15415
+ }
15416
+ }
15417
+ setMessages(
15418
+ (prev) => prev.map(
15419
+ (m2) => m2.id === assistantMessage.id ? {
15420
+ ...m2,
15421
+ toolInvocations: [...toolInvocationsAccumulated],
15422
+ parts: [...partsAccumulated]
15423
+ } : m2
15424
+ )
15425
+ );
15305
15426
  } else if (chunk.type === "error") {
15306
15427
  console.error("Stream error:", chunk.value);
15307
15428
  }
15308
15429
  }
15309
15430
  const processedResponse = await stream.response;
15310
15431
  const finalContent = processedResponse?.content || fullContent || "(No response)";
15432
+ const finalParts = [{ type: "step-start" }];
15433
+ if (finalContent) {
15434
+ finalParts.push({ type: "text", text: finalContent });
15435
+ }
15436
+ for (const inv of toolInvocationsAccumulated) {
15437
+ finalParts.push({ type: "tool-invocation", toolInvocation: inv });
15438
+ }
15311
15439
  setMessages(
15312
15440
  (prev) => prev.map(
15313
- (m2) => m2.id === assistantMessage.id ? { ...m2, isStreaming: false, content: finalContent } : m2
15441
+ (m2) => m2.id === assistantMessage.id ? {
15442
+ ...m2,
15443
+ isStreaming: false,
15444
+ content: finalContent,
15445
+ toolInvocations: toolInvocationsAccumulated.length > 0 ? toolInvocationsAccumulated : void 0,
15446
+ parts: toolInvocationsAccumulated.length > 0 ? finalParts : void 0
15447
+ } : m2
15314
15448
  )
15315
15449
  );
15316
15450
  onResponse?.(finalContent);