@emblemvault/hustle-react 1.4.1 → 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.
@@ -3623,7 +3623,14 @@ function HustleChat({
3623
3623
  setIsStreaming(true);
3624
3624
  setCurrentToolCalls([]);
3625
3625
  try {
3626
- const chatMessages = messagesRef.current.filter((m) => !m.isStreaming).map((m) => ({ role: m.role, content: m.content }));
3626
+ const chatMessages = messagesRef.current.filter((m) => !m.isStreaming).map((m) => {
3627
+ const msg = { role: m.role, content: m.content };
3628
+ if (m.role === "assistant" && m.toolInvocations && m.toolInvocations.length > 0) {
3629
+ msg.toolInvocations = m.toolInvocations;
3630
+ msg.parts = m.parts;
3631
+ }
3632
+ return msg;
3633
+ });
3627
3634
  chatMessages.push({ role: "user", content: "continue" });
3628
3635
  const stream = chatStream({
3629
3636
  messages: chatMessages,
@@ -3631,6 +3638,9 @@ function HustleChat({
3631
3638
  });
3632
3639
  let fullContent = "";
3633
3640
  const toolCallsAccumulated = [];
3641
+ const toolInvocationsAccumulated = [];
3642
+ const partsAccumulated = [{ type: "step-start" }];
3643
+ let stepCounter = 0;
3634
3644
  for await (const chunk of stream) {
3635
3645
  if (chunk.type === "text") {
3636
3646
  fullContent += chunk.value;
@@ -3642,22 +3652,79 @@ function HustleChat({
3642
3652
  } else if (chunk.type === "tool_call") {
3643
3653
  const toolCall = chunk.value;
3644
3654
  toolCallsAccumulated.push(toolCall);
3655
+ const invocation = {
3656
+ state: "call",
3657
+ step: stepCounter++,
3658
+ toolCallId: toolCall.toolCallId,
3659
+ toolName: toolCall.toolName,
3660
+ args: toolCall.args
3661
+ };
3662
+ toolInvocationsAccumulated.push(invocation);
3663
+ partsAccumulated.push({ type: "tool-invocation", toolInvocation: invocation });
3645
3664
  setCurrentToolCalls([...toolCallsAccumulated]);
3646
3665
  setMessages(
3647
3666
  (prev) => prev.map(
3648
- (m) => m.id === assistantMessage.id ? { ...m, toolCalls: [...toolCallsAccumulated] } : m
3667
+ (m) => m.id === assistantMessage.id ? {
3668
+ ...m,
3669
+ toolCalls: [...toolCallsAccumulated],
3670
+ toolInvocations: [...toolInvocationsAccumulated],
3671
+ parts: [...partsAccumulated]
3672
+ } : m
3649
3673
  )
3650
3674
  );
3651
3675
  onToolCall?.(toolCall);
3676
+ } else if (chunk.type === "tool_result") {
3677
+ const toolResult = chunk.value;
3678
+ const invocationIndex = toolInvocationsAccumulated.findIndex(
3679
+ (inv) => inv.toolCallId === toolResult.toolCallId
3680
+ );
3681
+ if (invocationIndex !== -1) {
3682
+ toolInvocationsAccumulated[invocationIndex] = {
3683
+ ...toolInvocationsAccumulated[invocationIndex],
3684
+ state: "result",
3685
+ result: toolResult.result
3686
+ };
3687
+ const partIndex = partsAccumulated.findIndex(
3688
+ (p) => p.type === "tool-invocation" && p.toolInvocation.toolCallId === toolResult.toolCallId
3689
+ );
3690
+ if (partIndex !== -1) {
3691
+ partsAccumulated[partIndex] = {
3692
+ type: "tool-invocation",
3693
+ toolInvocation: toolInvocationsAccumulated[invocationIndex]
3694
+ };
3695
+ }
3696
+ }
3697
+ setMessages(
3698
+ (prev) => prev.map(
3699
+ (m) => m.id === assistantMessage.id ? {
3700
+ ...m,
3701
+ toolInvocations: [...toolInvocationsAccumulated],
3702
+ parts: [...partsAccumulated]
3703
+ } : m
3704
+ )
3705
+ );
3652
3706
  } else if (chunk.type === "error") {
3653
3707
  console.error("Stream error:", chunk.value);
3654
3708
  }
3655
3709
  }
3656
3710
  const processedResponse = await stream.response;
3657
3711
  const finalContent = processedResponse?.content || fullContent || "(No response)";
3712
+ const finalParts = [{ type: "step-start" }];
3713
+ if (finalContent) {
3714
+ finalParts.push({ type: "text", text: finalContent });
3715
+ }
3716
+ for (const inv of toolInvocationsAccumulated) {
3717
+ finalParts.push({ type: "tool-invocation", toolInvocation: inv });
3718
+ }
3658
3719
  setMessages(
3659
3720
  (prev) => prev.map(
3660
- (m) => m.id === assistantMessage.id ? { ...m, isStreaming: false, content: finalContent } : m
3721
+ (m) => m.id === assistantMessage.id ? {
3722
+ ...m,
3723
+ isStreaming: false,
3724
+ content: finalContent,
3725
+ toolInvocations: toolInvocationsAccumulated.length > 0 ? toolInvocationsAccumulated : void 0,
3726
+ parts: toolInvocationsAccumulated.length > 0 ? finalParts : void 0
3727
+ } : m
3661
3728
  )
3662
3729
  );
3663
3730
  onResponse?.(finalContent);
@@ -3719,7 +3786,14 @@ function HustleChat({
3719
3786
  setIsStreaming(true);
3720
3787
  setCurrentToolCalls([]);
3721
3788
  try {
3722
- const chatMessages = messages.filter((m) => !m.isStreaming).map((m) => ({ role: m.role, content: m.content }));
3789
+ const chatMessages = messages.filter((m) => !m.isStreaming).map((m) => {
3790
+ const msg = { role: m.role, content: m.content };
3791
+ if (m.role === "assistant" && m.toolInvocations && m.toolInvocations.length > 0) {
3792
+ msg.toolInvocations = m.toolInvocations;
3793
+ msg.parts = m.parts;
3794
+ }
3795
+ return msg;
3796
+ });
3723
3797
  chatMessages.push({ role: "user", content });
3724
3798
  const stream = chatStream({
3725
3799
  messages: chatMessages,
@@ -3729,6 +3803,9 @@ function HustleChat({
3729
3803
  setAttachments([]);
3730
3804
  let fullContent = "";
3731
3805
  const toolCallsAccumulated = [];
3806
+ const toolInvocationsAccumulated = [];
3807
+ const partsAccumulated = [{ type: "step-start" }];
3808
+ let stepCounter = 0;
3732
3809
  for await (const chunk of stream) {
3733
3810
  if (chunk.type === "text") {
3734
3811
  fullContent += chunk.value;
@@ -3740,22 +3817,79 @@ function HustleChat({
3740
3817
  } else if (chunk.type === "tool_call") {
3741
3818
  const toolCall = chunk.value;
3742
3819
  toolCallsAccumulated.push(toolCall);
3820
+ const invocation = {
3821
+ state: "call",
3822
+ step: stepCounter++,
3823
+ toolCallId: toolCall.toolCallId,
3824
+ toolName: toolCall.toolName,
3825
+ args: toolCall.args
3826
+ };
3827
+ toolInvocationsAccumulated.push(invocation);
3828
+ partsAccumulated.push({ type: "tool-invocation", toolInvocation: invocation });
3743
3829
  setCurrentToolCalls([...toolCallsAccumulated]);
3744
3830
  setMessages(
3745
3831
  (prev) => prev.map(
3746
- (m) => m.id === assistantMessage.id ? { ...m, toolCalls: [...toolCallsAccumulated] } : m
3832
+ (m) => m.id === assistantMessage.id ? {
3833
+ ...m,
3834
+ toolCalls: [...toolCallsAccumulated],
3835
+ toolInvocations: [...toolInvocationsAccumulated],
3836
+ parts: [...partsAccumulated]
3837
+ } : m
3747
3838
  )
3748
3839
  );
3749
3840
  onToolCall?.(toolCall);
3841
+ } else if (chunk.type === "tool_result") {
3842
+ const toolResult = chunk.value;
3843
+ const invocationIndex = toolInvocationsAccumulated.findIndex(
3844
+ (inv) => inv.toolCallId === toolResult.toolCallId
3845
+ );
3846
+ if (invocationIndex !== -1) {
3847
+ toolInvocationsAccumulated[invocationIndex] = {
3848
+ ...toolInvocationsAccumulated[invocationIndex],
3849
+ state: "result",
3850
+ result: toolResult.result
3851
+ };
3852
+ const partIndex = partsAccumulated.findIndex(
3853
+ (p) => p.type === "tool-invocation" && p.toolInvocation.toolCallId === toolResult.toolCallId
3854
+ );
3855
+ if (partIndex !== -1) {
3856
+ partsAccumulated[partIndex] = {
3857
+ type: "tool-invocation",
3858
+ toolInvocation: toolInvocationsAccumulated[invocationIndex]
3859
+ };
3860
+ }
3861
+ }
3862
+ setMessages(
3863
+ (prev) => prev.map(
3864
+ (m) => m.id === assistantMessage.id ? {
3865
+ ...m,
3866
+ toolInvocations: [...toolInvocationsAccumulated],
3867
+ parts: [...partsAccumulated]
3868
+ } : m
3869
+ )
3870
+ );
3750
3871
  } else if (chunk.type === "error") {
3751
3872
  console.error("Stream error:", chunk.value);
3752
3873
  }
3753
3874
  }
3754
3875
  const processedResponse = await stream.response;
3755
3876
  const finalContent = processedResponse?.content || fullContent || "(No response)";
3877
+ const finalParts = [{ type: "step-start" }];
3878
+ if (finalContent) {
3879
+ finalParts.push({ type: "text", text: finalContent });
3880
+ }
3881
+ for (const inv of toolInvocationsAccumulated) {
3882
+ finalParts.push({ type: "tool-invocation", toolInvocation: inv });
3883
+ }
3756
3884
  setMessages(
3757
3885
  (prev) => prev.map(
3758
- (m) => m.id === assistantMessage.id ? { ...m, isStreaming: false, content: finalContent } : m
3886
+ (m) => m.id === assistantMessage.id ? {
3887
+ ...m,
3888
+ isStreaming: false,
3889
+ content: finalContent,
3890
+ toolInvocations: toolInvocationsAccumulated.length > 0 ? toolInvocationsAccumulated : void 0,
3891
+ parts: toolInvocationsAccumulated.length > 0 ? finalParts : void 0
3892
+ } : m
3759
3893
  )
3760
3894
  );
3761
3895
  onResponse?.(finalContent);