@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.
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { HustleProvider, useHustle } from './providers/index.cjs';
2
2
  export { HustleChat, HustleChatProps, HustleChatWidget, HustleChatWidgetConfig, HustleChatWidgetProps, MarkdownContent, WidgetPosition, WidgetSize } from './components/index.cjs';
3
- export { A as Attachment, C as ChatMessage, b as ChatOptions, d as ChatResponse, H as HustleConfig, h as HustleContextValue, i as HustleProviderProps, M as Model, c as StreamChunk, g as StreamEndEvent, S as StreamOptions, T as ToolCall, f as ToolEndEvent, a as ToolResult, e as ToolStartEvent } from './hustle-S48t4lTZ.cjs';
3
+ export { A as Attachment, C as ChatMessage, b as ChatOptions, d as ChatResponse, H as HustleConfig, h as HustleContextValue, i as HustleProviderProps, M as Model, c as StreamChunk, g as StreamEndEvent, S as StreamOptions, T as ToolCall, f as ToolEndEvent, a as ToolResult, e as ToolStartEvent } from './hustle-C0Ltl5k4.cjs';
4
4
  import { S as StoredPlugin, H as HustlePlugin, a as HydratedPlugin } from './plugin-COr42J6-.cjs';
5
5
  export { C as ClientToolDefinition, E as ErrorContext, d as HustleRequest, J as JSONSchema, b as JSONSchemaProperty, e as PluginHooks, P as ProcessedResponse, f as SerializedHooks, c as SerializedToolDefinition, T as ToolExecutor } from './plugin-COr42J6-.cjs';
6
6
  export { UsePluginsReturn, usePlugins } from './hooks/index.cjs';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { HustleProvider, useHustle } from './providers/index.js';
2
2
  export { HustleChat, HustleChatProps, HustleChatWidget, HustleChatWidgetConfig, HustleChatWidgetProps, MarkdownContent, WidgetPosition, WidgetSize } from './components/index.js';
3
- export { A as Attachment, C as ChatMessage, b as ChatOptions, d as ChatResponse, H as HustleConfig, h as HustleContextValue, i as HustleProviderProps, M as Model, c as StreamChunk, g as StreamEndEvent, S as StreamOptions, T as ToolCall, f as ToolEndEvent, a as ToolResult, e as ToolStartEvent } from './hustle-S48t4lTZ.js';
3
+ export { A as Attachment, C as ChatMessage, b as ChatOptions, d as ChatResponse, H as HustleConfig, h as HustleContextValue, i as HustleProviderProps, M as Model, c as StreamChunk, g as StreamEndEvent, S as StreamOptions, T as ToolCall, f as ToolEndEvent, a as ToolResult, e as ToolStartEvent } from './hustle-C0Ltl5k4.js';
4
4
  import { S as StoredPlugin, H as HustlePlugin, a as HydratedPlugin } from './plugin-COr42J6-.js';
5
5
  export { C as ClientToolDefinition, E as ErrorContext, d as HustleRequest, J as JSONSchema, b as JSONSchemaProperty, e as PluginHooks, P as ProcessedResponse, f as SerializedHooks, c as SerializedToolDefinition, T as ToolExecutor } from './plugin-COr42J6-.js';
6
6
  export { UsePluginsReturn, usePlugins } from './hooks/index.js';
package/dist/index.js CHANGED
@@ -4023,7 +4023,14 @@ function HustleChat({
4023
4023
  setIsStreaming(true);
4024
4024
  setCurrentToolCalls([]);
4025
4025
  try {
4026
- const chatMessages = messagesRef.current.filter((m) => !m.isStreaming).map((m) => ({ role: m.role, content: m.content }));
4026
+ const chatMessages = messagesRef.current.filter((m) => !m.isStreaming).map((m) => {
4027
+ const msg = { role: m.role, content: m.content };
4028
+ if (m.role === "assistant" && m.toolInvocations && m.toolInvocations.length > 0) {
4029
+ msg.toolInvocations = m.toolInvocations;
4030
+ msg.parts = m.parts;
4031
+ }
4032
+ return msg;
4033
+ });
4027
4034
  chatMessages.push({ role: "user", content: "continue" });
4028
4035
  const stream = chatStream({
4029
4036
  messages: chatMessages,
@@ -4031,6 +4038,9 @@ function HustleChat({
4031
4038
  });
4032
4039
  let fullContent = "";
4033
4040
  const toolCallsAccumulated = [];
4041
+ const toolInvocationsAccumulated = [];
4042
+ const partsAccumulated = [{ type: "step-start" }];
4043
+ let stepCounter = 0;
4034
4044
  for await (const chunk of stream) {
4035
4045
  if (chunk.type === "text") {
4036
4046
  fullContent += chunk.value;
@@ -4042,22 +4052,79 @@ function HustleChat({
4042
4052
  } else if (chunk.type === "tool_call") {
4043
4053
  const toolCall = chunk.value;
4044
4054
  toolCallsAccumulated.push(toolCall);
4055
+ const invocation = {
4056
+ state: "call",
4057
+ step: stepCounter++,
4058
+ toolCallId: toolCall.toolCallId,
4059
+ toolName: toolCall.toolName,
4060
+ args: toolCall.args
4061
+ };
4062
+ toolInvocationsAccumulated.push(invocation);
4063
+ partsAccumulated.push({ type: "tool-invocation", toolInvocation: invocation });
4045
4064
  setCurrentToolCalls([...toolCallsAccumulated]);
4046
4065
  setMessages(
4047
4066
  (prev) => prev.map(
4048
- (m) => m.id === assistantMessage.id ? { ...m, toolCalls: [...toolCallsAccumulated] } : m
4067
+ (m) => m.id === assistantMessage.id ? {
4068
+ ...m,
4069
+ toolCalls: [...toolCallsAccumulated],
4070
+ toolInvocations: [...toolInvocationsAccumulated],
4071
+ parts: [...partsAccumulated]
4072
+ } : m
4049
4073
  )
4050
4074
  );
4051
4075
  onToolCall?.(toolCall);
4076
+ } else if (chunk.type === "tool_result") {
4077
+ const toolResult = chunk.value;
4078
+ const invocationIndex = toolInvocationsAccumulated.findIndex(
4079
+ (inv) => inv.toolCallId === toolResult.toolCallId
4080
+ );
4081
+ if (invocationIndex !== -1) {
4082
+ toolInvocationsAccumulated[invocationIndex] = {
4083
+ ...toolInvocationsAccumulated[invocationIndex],
4084
+ state: "result",
4085
+ result: toolResult.result
4086
+ };
4087
+ const partIndex = partsAccumulated.findIndex(
4088
+ (p) => p.type === "tool-invocation" && p.toolInvocation.toolCallId === toolResult.toolCallId
4089
+ );
4090
+ if (partIndex !== -1) {
4091
+ partsAccumulated[partIndex] = {
4092
+ type: "tool-invocation",
4093
+ toolInvocation: toolInvocationsAccumulated[invocationIndex]
4094
+ };
4095
+ }
4096
+ }
4097
+ setMessages(
4098
+ (prev) => prev.map(
4099
+ (m) => m.id === assistantMessage.id ? {
4100
+ ...m,
4101
+ toolInvocations: [...toolInvocationsAccumulated],
4102
+ parts: [...partsAccumulated]
4103
+ } : m
4104
+ )
4105
+ );
4052
4106
  } else if (chunk.type === "error") {
4053
4107
  console.error("Stream error:", chunk.value);
4054
4108
  }
4055
4109
  }
4056
4110
  const processedResponse = await stream.response;
4057
4111
  const finalContent = processedResponse?.content || fullContent || "(No response)";
4112
+ const finalParts = [{ type: "step-start" }];
4113
+ if (finalContent) {
4114
+ finalParts.push({ type: "text", text: finalContent });
4115
+ }
4116
+ for (const inv of toolInvocationsAccumulated) {
4117
+ finalParts.push({ type: "tool-invocation", toolInvocation: inv });
4118
+ }
4058
4119
  setMessages(
4059
4120
  (prev) => prev.map(
4060
- (m) => m.id === assistantMessage.id ? { ...m, isStreaming: false, content: finalContent } : m
4121
+ (m) => m.id === assistantMessage.id ? {
4122
+ ...m,
4123
+ isStreaming: false,
4124
+ content: finalContent,
4125
+ toolInvocations: toolInvocationsAccumulated.length > 0 ? toolInvocationsAccumulated : void 0,
4126
+ parts: toolInvocationsAccumulated.length > 0 ? finalParts : void 0
4127
+ } : m
4061
4128
  )
4062
4129
  );
4063
4130
  onResponse?.(finalContent);
@@ -4119,7 +4186,14 @@ function HustleChat({
4119
4186
  setIsStreaming(true);
4120
4187
  setCurrentToolCalls([]);
4121
4188
  try {
4122
- const chatMessages = messages.filter((m) => !m.isStreaming).map((m) => ({ role: m.role, content: m.content }));
4189
+ const chatMessages = messages.filter((m) => !m.isStreaming).map((m) => {
4190
+ const msg = { role: m.role, content: m.content };
4191
+ if (m.role === "assistant" && m.toolInvocations && m.toolInvocations.length > 0) {
4192
+ msg.toolInvocations = m.toolInvocations;
4193
+ msg.parts = m.parts;
4194
+ }
4195
+ return msg;
4196
+ });
4123
4197
  chatMessages.push({ role: "user", content });
4124
4198
  const stream = chatStream({
4125
4199
  messages: chatMessages,
@@ -4129,6 +4203,9 @@ function HustleChat({
4129
4203
  setAttachments([]);
4130
4204
  let fullContent = "";
4131
4205
  const toolCallsAccumulated = [];
4206
+ const toolInvocationsAccumulated = [];
4207
+ const partsAccumulated = [{ type: "step-start" }];
4208
+ let stepCounter = 0;
4132
4209
  for await (const chunk of stream) {
4133
4210
  if (chunk.type === "text") {
4134
4211
  fullContent += chunk.value;
@@ -4140,22 +4217,79 @@ function HustleChat({
4140
4217
  } else if (chunk.type === "tool_call") {
4141
4218
  const toolCall = chunk.value;
4142
4219
  toolCallsAccumulated.push(toolCall);
4220
+ const invocation = {
4221
+ state: "call",
4222
+ step: stepCounter++,
4223
+ toolCallId: toolCall.toolCallId,
4224
+ toolName: toolCall.toolName,
4225
+ args: toolCall.args
4226
+ };
4227
+ toolInvocationsAccumulated.push(invocation);
4228
+ partsAccumulated.push({ type: "tool-invocation", toolInvocation: invocation });
4143
4229
  setCurrentToolCalls([...toolCallsAccumulated]);
4144
4230
  setMessages(
4145
4231
  (prev) => prev.map(
4146
- (m) => m.id === assistantMessage.id ? { ...m, toolCalls: [...toolCallsAccumulated] } : m
4232
+ (m) => m.id === assistantMessage.id ? {
4233
+ ...m,
4234
+ toolCalls: [...toolCallsAccumulated],
4235
+ toolInvocations: [...toolInvocationsAccumulated],
4236
+ parts: [...partsAccumulated]
4237
+ } : m
4147
4238
  )
4148
4239
  );
4149
4240
  onToolCall?.(toolCall);
4241
+ } else if (chunk.type === "tool_result") {
4242
+ const toolResult = chunk.value;
4243
+ const invocationIndex = toolInvocationsAccumulated.findIndex(
4244
+ (inv) => inv.toolCallId === toolResult.toolCallId
4245
+ );
4246
+ if (invocationIndex !== -1) {
4247
+ toolInvocationsAccumulated[invocationIndex] = {
4248
+ ...toolInvocationsAccumulated[invocationIndex],
4249
+ state: "result",
4250
+ result: toolResult.result
4251
+ };
4252
+ const partIndex = partsAccumulated.findIndex(
4253
+ (p) => p.type === "tool-invocation" && p.toolInvocation.toolCallId === toolResult.toolCallId
4254
+ );
4255
+ if (partIndex !== -1) {
4256
+ partsAccumulated[partIndex] = {
4257
+ type: "tool-invocation",
4258
+ toolInvocation: toolInvocationsAccumulated[invocationIndex]
4259
+ };
4260
+ }
4261
+ }
4262
+ setMessages(
4263
+ (prev) => prev.map(
4264
+ (m) => m.id === assistantMessage.id ? {
4265
+ ...m,
4266
+ toolInvocations: [...toolInvocationsAccumulated],
4267
+ parts: [...partsAccumulated]
4268
+ } : m
4269
+ )
4270
+ );
4150
4271
  } else if (chunk.type === "error") {
4151
4272
  console.error("Stream error:", chunk.value);
4152
4273
  }
4153
4274
  }
4154
4275
  const processedResponse = await stream.response;
4155
4276
  const finalContent = processedResponse?.content || fullContent || "(No response)";
4277
+ const finalParts = [{ type: "step-start" }];
4278
+ if (finalContent) {
4279
+ finalParts.push({ type: "text", text: finalContent });
4280
+ }
4281
+ for (const inv of toolInvocationsAccumulated) {
4282
+ finalParts.push({ type: "tool-invocation", toolInvocation: inv });
4283
+ }
4156
4284
  setMessages(
4157
4285
  (prev) => prev.map(
4158
- (m) => m.id === assistantMessage.id ? { ...m, isStreaming: false, content: finalContent } : m
4286
+ (m) => m.id === assistantMessage.id ? {
4287
+ ...m,
4288
+ isStreaming: false,
4289
+ content: finalContent,
4290
+ toolInvocations: toolInvocationsAccumulated.length > 0 ? toolInvocationsAccumulated : void 0,
4291
+ parts: toolInvocationsAccumulated.length > 0 ? finalParts : void 0
4292
+ } : m
4159
4293
  )
4160
4294
  );
4161
4295
  onResponse?.(finalContent);