@astralform/js 0.1.0 → 0.1.2

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.cjs CHANGED
@@ -285,6 +285,11 @@ var AstralformClient = class {
285
285
  isEnabled: s.is_enabled
286
286
  }));
287
287
  }
288
+ async getConversationEvents(conversationId) {
289
+ return this.get(
290
+ `/v1/conversations/${encodeURIComponent(conversationId)}/events`
291
+ );
292
+ }
288
293
  async submitToolResult(request) {
289
294
  await this.post("/v1/tool-result", request);
290
295
  }
@@ -607,7 +612,8 @@ var ChatSession = class {
607
612
  options?.enabledClientTools ?? this.enabledClientTools
608
613
  ),
609
614
  upload_ids: options?.uploadIds,
610
- agent_name: options?.agentName
615
+ agent_name: options?.agentName,
616
+ enable_search: options?.enableSearch
611
617
  };
612
618
  await this.processStream(request);
613
619
  }
@@ -622,8 +628,7 @@ var ChatSession = class {
622
628
  };
623
629
  await this.processStream(request);
624
630
  }
625
- async processStream(request) {
626
- this.isStreaming = true;
631
+ resetStreamingState() {
627
632
  this.streamingContent = "";
628
633
  this.thinkingContent = "";
629
634
  this.isThinking = false;
@@ -632,6 +637,10 @@ var ChatSession = class {
632
637
  this.capsuleOutputs = [];
633
638
  this.todos = [];
634
639
  this.activeTools.clear();
640
+ }
641
+ async processStream(request) {
642
+ this.isStreaming = true;
643
+ this.resetStreamingState();
635
644
  this.abortController = new AbortController();
636
645
  try {
637
646
  await this.consumeJobStream(request);
@@ -691,39 +700,26 @@ var ChatSession = class {
691
700
  name: parsed.model_display_name
692
701
  });
693
702
  }
694
- if (parsed.agent_name) {
695
- this.emit({
696
- type: "agent_start",
697
- agentName: parsed.agent_name,
698
- agentDisplayName: parsed.agent_display_name
699
- });
700
- }
701
703
  break;
702
704
  case "content_block_delta":
703
705
  this.streamingContent += parsed.delta.text;
704
706
  this.emit({ type: "chunk", text: parsed.delta.text });
705
707
  break;
706
708
  case "tool_use_start": {
707
- const toolCall = {
708
- callId: parsed.call_id,
709
- toolName: parsed.tool,
710
- displayName: parsed.display_name,
711
- description: parsed.description,
712
- arguments: parsed.arguments,
713
- isClientTool: parsed.is_client_tool
714
- };
715
- this.activeTools.set(parsed.call_id, {
716
- toolName: parsed.tool,
717
- displayName: parsed.display_name,
718
- description: parsed.description,
719
- arguments: parsed.arguments,
720
- callId: parsed.call_id,
721
- status: parsed.is_client_tool ? "calling" : "executing",
722
- isClientTool: parsed.is_client_tool
723
- });
724
- this.emit({ type: "tool_call", request: toolCall });
709
+ this.applyEvent(parsed);
725
710
  if (parsed.is_client_tool) {
726
- const results = await this.executeClientTools([toolCall]);
711
+ const results = await this.executeClientTools([
712
+ {
713
+ callId: parsed.call_id,
714
+ toolName: parsed.tool,
715
+ displayName: parsed.display_name,
716
+ description: parsed.description,
717
+ arguments: parsed.arguments,
718
+ isClientTool: parsed.is_client_tool,
719
+ toolCategory: parsed.tool_category,
720
+ iconUrl: parsed.icon_url
721
+ }
722
+ ]);
727
723
  await this.client.submitToolResult({
728
724
  conversation_id: conversationId,
729
725
  message_id: messageId,
@@ -732,61 +728,6 @@ var ChatSession = class {
732
728
  }
733
729
  break;
734
730
  }
735
- case "tool_use_end": {
736
- const toolState = this.activeTools.get(parsed.call_id);
737
- if (toolState) {
738
- toolState.status = "completed";
739
- }
740
- this.emit({
741
- type: "tool_end",
742
- callId: parsed.call_id,
743
- toolName: parsed.tool
744
- });
745
- break;
746
- }
747
- case "agent_start":
748
- this.emit({
749
- type: "agent_start",
750
- agentName: parsed.agent_name,
751
- agentDisplayName: parsed.agent_display_name,
752
- avatarUrl: parsed.avatar_url
753
- });
754
- break;
755
- case "agent_end":
756
- this.emit({ type: "agent_end", agentName: parsed.agent_name });
757
- break;
758
- case "subagent_start":
759
- this.activeSubagents.set(parsed.tool_call_id, {
760
- agentName: parsed.agent_name,
761
- displayName: parsed.display_name,
762
- avatarUrl: parsed.avatar_url,
763
- description: parsed.description,
764
- content: "",
765
- isActive: true
766
- });
767
- this.emit({
768
- type: "subagent_start",
769
- agentName: parsed.agent_name,
770
- displayName: parsed.display_name,
771
- toolCallId: parsed.tool_call_id,
772
- avatarUrl: parsed.avatar_url,
773
- description: parsed.description
774
- });
775
- break;
776
- case "subagent_update": {
777
- const sub = this.activeSubagents.get(parsed.tool_call_id);
778
- if (sub) {
779
- sub.agentName = parsed.agent_name;
780
- sub.displayName = parsed.display_name;
781
- }
782
- this.emit({
783
- type: "subagent_update",
784
- agentName: parsed.agent_name,
785
- displayName: parsed.display_name,
786
- toolCallId: parsed.tool_call_id
787
- });
788
- break;
789
- }
790
731
  case "subagent_content_delta": {
791
732
  const subagent = this.activeSubagents.get(parsed.tool_call_id);
792
733
  if (subagent) {
@@ -800,19 +741,6 @@ var ChatSession = class {
800
741
  });
801
742
  break;
802
743
  }
803
- case "subagent_end": {
804
- const sub = this.activeSubagents.get(parsed.tool_call_id);
805
- if (sub) {
806
- sub.isActive = false;
807
- }
808
- this.emit({
809
- type: "subagent_end",
810
- agentName: parsed.agent_name,
811
- displayName: parsed.display_name,
812
- toolCallId: parsed.tool_call_id
813
- });
814
- break;
815
- }
816
744
  case "thinking_delta":
817
745
  this.thinkingContent += parsed.delta.text;
818
746
  this.isThinking = true;
@@ -822,45 +750,6 @@ var ChatSession = class {
822
750
  this.isThinking = false;
823
751
  this.emit({ type: "thinking_complete" });
824
752
  break;
825
- case "sources":
826
- this.sources.push(...parsed.sources);
827
- this.emit({ type: "sources", sources: parsed.sources });
828
- break;
829
- case "capsule_output": {
830
- const capsule = {
831
- toolName: parsed.tool_name,
832
- agentName: parsed.agent_name,
833
- command: parsed.command,
834
- output: parsed.output,
835
- durationMs: parsed.duration_ms
836
- };
837
- this.capsuleOutputs.push(capsule);
838
- this.emit({ type: "capsule_output", ...capsule });
839
- break;
840
- }
841
- case "todo_update":
842
- this.todos = parsed.todos;
843
- this.emit({ type: "todo_update", todos: parsed.todos });
844
- break;
845
- case "subagent_tool_use":
846
- this.emit({
847
- type: "subagent_tool_use",
848
- agentName: parsed.agent_name,
849
- toolName: parsed.tool,
850
- toolCallId: parsed.tool_call_id,
851
- result: parsed.result
852
- });
853
- break;
854
- case "asset_created":
855
- this.emit({
856
- type: "asset_created",
857
- assetId: parsed.asset_id,
858
- name: parsed.name,
859
- url: parsed.url,
860
- mediaType: parsed.media_type,
861
- sizeBytes: parsed.size_bytes
862
- });
863
- break;
864
753
  case "retry":
865
754
  this.emit({
866
755
  type: "retry",
@@ -878,11 +767,170 @@ var ChatSession = class {
878
767
  error: new AstralformError(parsed.message, parsed.code)
879
768
  });
880
769
  break;
770
+ default:
771
+ this.applyEvent(parsed);
881
772
  }
882
773
  }
883
774
  this.currentJobId = null;
884
775
  await this.completeStream(conversationId, messageId, stopTitle);
885
776
  }
777
+ /**
778
+ * Apply a single SSE event to session state and notify consumers.
779
+ * Shared between live streaming and historical event replay.
780
+ */
781
+ applyEvent(event) {
782
+ switch (event.type) {
783
+ case "tool_use_start": {
784
+ const request = {
785
+ callId: event.call_id,
786
+ toolName: event.tool,
787
+ displayName: event.display_name,
788
+ description: event.description,
789
+ arguments: event.arguments,
790
+ isClientTool: event.is_client_tool,
791
+ toolCategory: event.tool_category,
792
+ iconUrl: event.icon_url
793
+ };
794
+ this.activeTools.set(event.call_id, {
795
+ ...request,
796
+ status: event.is_client_tool ? "calling" : "executing"
797
+ });
798
+ this.emit({ type: "tool_call", request });
799
+ break;
800
+ }
801
+ case "tool_use_end": {
802
+ const toolState = this.activeTools.get(event.call_id);
803
+ if (toolState) {
804
+ toolState.status = "completed";
805
+ }
806
+ this.emit({
807
+ type: "tool_end",
808
+ callId: event.call_id,
809
+ toolName: event.tool,
810
+ result: event.result
811
+ });
812
+ break;
813
+ }
814
+ case "agent_start":
815
+ this.emit({
816
+ type: "agent_start",
817
+ agentName: event.agent_name,
818
+ agentDisplayName: event.agent_display_name,
819
+ avatarUrl: event.avatar_url
820
+ });
821
+ break;
822
+ case "agent_end":
823
+ this.emit({ type: "agent_end", agentName: event.agent_name });
824
+ break;
825
+ case "subagent_start":
826
+ this.activeSubagents.set(event.tool_call_id, {
827
+ agentName: event.agent_name,
828
+ displayName: event.display_name,
829
+ avatarUrl: event.avatar_url,
830
+ description: event.description,
831
+ content: "",
832
+ isActive: true
833
+ });
834
+ this.emit({
835
+ type: "subagent_start",
836
+ agentName: event.agent_name,
837
+ displayName: event.display_name,
838
+ toolCallId: event.tool_call_id,
839
+ avatarUrl: event.avatar_url,
840
+ description: event.description
841
+ });
842
+ break;
843
+ case "subagent_update": {
844
+ const sub = this.activeSubagents.get(event.tool_call_id);
845
+ if (sub) {
846
+ sub.agentName = event.agent_name;
847
+ sub.displayName = event.display_name;
848
+ }
849
+ this.emit({
850
+ type: "subagent_update",
851
+ agentName: event.agent_name,
852
+ displayName: event.display_name,
853
+ toolCallId: event.tool_call_id
854
+ });
855
+ break;
856
+ }
857
+ case "subagent_end": {
858
+ const sub = this.activeSubagents.get(event.tool_call_id);
859
+ if (sub) {
860
+ sub.isActive = false;
861
+ }
862
+ this.emit({
863
+ type: "subagent_end",
864
+ agentName: event.agent_name,
865
+ displayName: event.display_name,
866
+ toolCallId: event.tool_call_id
867
+ });
868
+ break;
869
+ }
870
+ case "subagent_tool_use":
871
+ this.emit({
872
+ type: "subagent_tool_use",
873
+ agentName: event.agent_name,
874
+ toolName: event.tool,
875
+ toolCallId: event.tool_call_id,
876
+ result: event.result
877
+ });
878
+ break;
879
+ case "sources":
880
+ this.sources.push(...event.sources);
881
+ this.emit({ type: "sources", sources: event.sources });
882
+ break;
883
+ case "capsule_output": {
884
+ const capsule = {
885
+ toolName: event.tool_name,
886
+ agentName: event.agent_name,
887
+ command: event.command,
888
+ output: event.output,
889
+ durationMs: event.duration_ms,
890
+ callId: event.call_id
891
+ };
892
+ this.capsuleOutputs.push(capsule);
893
+ this.emit({ type: "capsule_output", ...capsule });
894
+ break;
895
+ }
896
+ case "capsule_output_chunk":
897
+ this.emit({
898
+ type: "capsule_output_chunk",
899
+ callId: event.call_id,
900
+ stream: event.stream,
901
+ chunk: event.chunk
902
+ });
903
+ break;
904
+ case "todo_update":
905
+ this.todos = event.todos;
906
+ this.emit({ type: "todo_update", todos: event.todos });
907
+ break;
908
+ case "asset_created":
909
+ this.emit({
910
+ type: "asset_created",
911
+ assetId: event.asset_id,
912
+ name: event.name,
913
+ url: event.url,
914
+ mediaType: event.media_type,
915
+ sizeBytes: event.size_bytes
916
+ });
917
+ break;
918
+ case "activity":
919
+ this.emit({
920
+ type: "activity",
921
+ activityId: event.activity_id,
922
+ status: event.status,
923
+ category: event.category,
924
+ title: event.title,
925
+ detail: event.detail,
926
+ sources: event.sources,
927
+ toolName: event.tool_name,
928
+ agentName: event.agent_name,
929
+ durationMs: event.duration_ms
930
+ });
931
+ break;
932
+ }
933
+ }
886
934
  async executeClientTools(toolCalls) {
887
935
  const results = [];
888
936
  for (const call of toolCalls) {
@@ -959,12 +1007,27 @@ var ChatSession = class {
959
1007
  }
960
1008
  async switchConversation(id) {
961
1009
  this.conversationId = id;
962
- try {
963
- this.messages = await this.client.getMessages(id);
964
- } catch {
965
- this.messages = await this.storage.fetchMessages(id);
1010
+ this.resetStreamingState();
1011
+ const [messagesResult, eventsResult] = await Promise.allSettled([
1012
+ this.client.getMessages(id).catch(() => this.storage.fetchMessages(id)),
1013
+ this.client.getConversationEvents(id)
1014
+ ]);
1015
+ this.messages = messagesResult.status === "fulfilled" ? messagesResult.value : [];
1016
+ if (eventsResult.status === "fulfilled") {
1017
+ for (const ev of eventsResult.value) {
1018
+ this.replayEvent(ev.event, ev.data);
1019
+ }
966
1020
  }
967
- this.streamingContent = "";
1021
+ }
1022
+ /**
1023
+ * Replay a single persisted event to reconstruct session state.
1024
+ * Skips text deltas (final content is already in messages[]).
1025
+ */
1026
+ replayEvent(eventType, data) {
1027
+ if (eventType === "content_block_delta" || eventType === "thinking_delta" || eventType === "subagent_content_delta" || eventType === "thinking_complete") {
1028
+ return;
1029
+ }
1030
+ this.applyEvent({ type: eventType, ...data });
968
1031
  }
969
1032
  async deleteConversation(id) {
970
1033
  try {