@agentscope-ai/chat 1.1.58 → 1.1.59

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.
@@ -124,6 +124,8 @@ export default function useChatController() {
124
124
 
125
125
  /**
126
126
  * 处理 SSE 重连(切回未完成的对话时)
127
+ * If the reconnect API returns no body or the stream ends without a completion event,
128
+ * treat it as idle: remove the empty placeholder and reset loading.
127
129
  */
128
130
  const handleReconnect = useCallback(async (sessionId: string) => {
129
131
  currentQARef.current.abortController = new AbortController();
@@ -132,6 +134,19 @@ export default function useChatController() {
132
134
  messageHandler.createResponseMessage();
133
135
 
134
136
  await reconnect(sessionId);
137
+
138
+ // If the response is still in 'generating' state after reconnect completes,
139
+ // onFinish() was never called (no response body, or stream closed without a completion event).
140
+ // Treat as idle: remove the empty placeholder and reset loading.
141
+ // HTTP errors and normal SSE completions both call onFinish() → msgStatus becomes 'finished',
142
+ // so they are correctly excluded from this cleanup.
143
+ if (currentQARef.current.response?.msgStatus === 'generating') {
144
+ setLoading(false);
145
+ if (currentQARef.current.response?.id) {
146
+ messageHandler.removeMessageById(currentQARef.current.response.id);
147
+ }
148
+ currentQARef.current.response = undefined;
149
+ }
135
150
  }, [messageHandler, reconnect, setLoading]);
136
151
 
137
152
  // 监听会话切换,断开当前 SSE 连接(不通知后端取消)并重置状态
@@ -66,7 +66,8 @@ export default function useChatRequest(options: UseChatRequestOptions) {
66
66
  });
67
67
 
68
68
  if (!response.ok) {
69
- response.json().then(data => {
69
+ try {
70
+ const data = await response.json();
70
71
  const res = agentScopeRuntimeResponseBuilder.handle({
71
72
  object: 'message',
72
73
  type: AgentScopeRuntimeMessageType.ERROR,
@@ -84,8 +85,10 @@ export default function useChatRequest(options: UseChatRequestOptions) {
84
85
  data: res,
85
86
  }
86
87
  ];
87
- onFinish();
88
- });
88
+ } catch {
89
+ // Ignore JSON parse errors — still call onFinish to reset loading state
90
+ }
91
+ onFinish();
89
92
  return;
90
93
  }
91
94
 
@@ -179,9 +179,13 @@ export default function useChatController() {
179
179
 
180
180
  /**
181
181
  * 处理 SSE 重连(切回未完成的对话时)
182
+ * If the reconnect API returns no body or the stream ends without a completion event,
183
+ * treat it as idle: remove the empty placeholder and reset loading.
182
184
  */
183
185
  var handleReconnect = useCallback( /*#__PURE__*/function () {
184
186
  var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(sessionId) {
187
+ var _currentQARef$current;
188
+ var _currentQARef$current2;
185
189
  return _regeneratorRuntime().wrap(function _callee4$(_context4) {
186
190
  while (1) switch (_context4.prev = _context4.next) {
187
191
  case 0:
@@ -191,6 +195,19 @@ export default function useChatController() {
191
195
  _context4.next = 5;
192
196
  return reconnect(sessionId);
193
197
  case 5:
198
+ // If the response is still in 'generating' state after reconnect completes,
199
+ // onFinish() was never called (no response body, or stream closed without a completion event).
200
+ // Treat as idle: remove the empty placeholder and reset loading.
201
+ // HTTP errors and normal SSE completions both call onFinish() → msgStatus becomes 'finished',
202
+ // so they are correctly excluded from this cleanup.
203
+ if (((_currentQARef$current = currentQARef.current.response) === null || _currentQARef$current === void 0 ? void 0 : _currentQARef$current.msgStatus) === 'generating') {
204
+ setLoading(false);
205
+ if ((_currentQARef$current2 = currentQARef.current.response) !== null && _currentQARef$current2 !== void 0 && _currentQARef$current2.id) {
206
+ messageHandler.removeMessageById(currentQARef.current.response.id);
207
+ }
208
+ currentQARef.current.response = undefined;
209
+ }
210
+ case 6:
194
211
  case "end":
195
212
  return _context4.stop();
196
213
  }
@@ -203,8 +220,8 @@ export default function useChatController() {
203
220
 
204
221
  // 监听会话切换,断开当前 SSE 连接(不通知后端取消)并重置状态
205
222
  useEffect(function () {
206
- var _currentQARef$current;
207
- (_currentQARef$current = currentQARef.current.abortController) === null || _currentQARef$current === void 0 || _currentQARef$current.abort();
223
+ var _currentQARef$current3;
224
+ (_currentQARef$current3 = currentQARef.current.abortController) === null || _currentQARef$current3 === void 0 || _currentQARef$current3.abort();
208
225
  currentQARef.current = {
209
226
  request: undefined,
210
227
  response: undefined,
@@ -102,7 +102,7 @@ export default function useChatRequest(options) {
102
102
  }(), []);
103
103
  var processSSEResponse = useCallback( /*#__PURE__*/function () {
104
104
  var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(response) {
105
- var currentApiOptions, agentScopeRuntimeResponseBuilder, _iteratorAbruptCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, chunk, _currentQARef$current, _res$output, _currentQARef$current2, responseParser, chunkData, res;
105
+ var currentApiOptions, agentScopeRuntimeResponseBuilder, data, res, _iteratorAbruptCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, chunk, _currentQARef$current, _res$output, _currentQARef$current2, responseParser, chunkData, _res;
106
106
  return _regeneratorRuntime().wrap(function _callee2$(_context2) {
107
107
  while (1) switch (_context2.prev = _context2.next) {
108
108
  case 0:
@@ -113,46 +113,55 @@ export default function useChatRequest(options) {
113
113
  created_at: 0
114
114
  });
115
115
  if (response.ok) {
116
- _context2.next = 5;
116
+ _context2.next = 15;
117
117
  break;
118
118
  }
119
- response.json().then(function (data) {
120
- var res = agentScopeRuntimeResponseBuilder.handle({
121
- object: 'message',
122
- type: AgentScopeRuntimeMessageType.ERROR,
123
- content: [],
124
- id: 'error',
125
- role: 'assistant',
126
- status: AgentScopeRuntimeRunStatus.Failed,
127
- code: String(response.status),
128
- message: JSON.stringify(data)
129
- });
130
- currentQARef.current.response.cards = [{
131
- code: 'AgentScopeRuntimeResponseCard',
132
- data: res
133
- }];
134
- onFinish();
119
+ _context2.prev = 3;
120
+ _context2.next = 6;
121
+ return response.json();
122
+ case 6:
123
+ data = _context2.sent;
124
+ res = agentScopeRuntimeResponseBuilder.handle({
125
+ object: 'message',
126
+ type: AgentScopeRuntimeMessageType.ERROR,
127
+ content: [],
128
+ id: 'error',
129
+ role: 'assistant',
130
+ status: AgentScopeRuntimeRunStatus.Failed,
131
+ code: String(response.status),
132
+ message: JSON.stringify(data)
135
133
  });
134
+ currentQARef.current.response.cards = [{
135
+ code: 'AgentScopeRuntimeResponseCard',
136
+ data: res
137
+ }];
138
+ _context2.next = 13;
139
+ break;
140
+ case 11:
141
+ _context2.prev = 11;
142
+ _context2.t0 = _context2["catch"](3);
143
+ case 13:
144
+ onFinish();
136
145
  return _context2.abrupt("return");
137
- case 5:
138
- _context2.prev = 5;
146
+ case 15:
147
+ _context2.prev = 15;
139
148
  _iteratorAbruptCompletion2 = false;
140
149
  _didIteratorError2 = false;
141
- _context2.prev = 8;
150
+ _context2.prev = 18;
142
151
  _iterator2 = _asyncIterator(Stream({
143
152
  readableStream: response.body
144
153
  }));
145
- case 10:
146
- _context2.next = 12;
154
+ case 20:
155
+ _context2.next = 22;
147
156
  return _iterator2.next();
148
- case 12:
157
+ case 22:
149
158
  if (!(_iteratorAbruptCompletion2 = !(_step2 = _context2.sent).done)) {
150
- _context2.next = 29;
159
+ _context2.next = 39;
151
160
  break;
152
161
  }
153
162
  chunk = _step2.value;
154
163
  if (!(((_currentQARef$current = currentQARef.current.response) === null || _currentQARef$current === void 0 ? void 0 : _currentQARef$current.msgStatus) === 'interrupted')) {
155
- _context2.next = 20;
164
+ _context2.next = 30;
156
165
  break;
157
166
  }
158
167
  (_currentQARef$current2 = currentQARef.current.abortController) === null || _currentQARef$current2 === void 0 || _currentQARef$current2.abort();
@@ -166,72 +175,72 @@ export default function useChatRequest(options) {
166
175
  data: agentScopeRuntimeResponseBuilder.cancel()
167
176
  }];
168
177
  updateMessage(currentQARef.current.response);
169
- return _context2.abrupt("break", 29);
170
- case 20:
178
+ return _context2.abrupt("break", 39);
179
+ case 30:
171
180
  responseParser = apiOptionsRef.current.responseParser || JSON.parse;
172
181
  chunkData = responseParser(chunk.data);
173
- res = agentScopeRuntimeResponseBuilder.handle(chunkData);
174
- if (!(res.status !== AgentScopeRuntimeRunStatus.Failed && !((_res$output = res.output) !== null && _res$output !== void 0 && (_res$output = _res$output[0]) !== null && _res$output !== void 0 && (_res$output = _res$output.content) !== null && _res$output !== void 0 && _res$output.length))) {
175
- _context2.next = 25;
182
+ _res = agentScopeRuntimeResponseBuilder.handle(chunkData);
183
+ if (!(_res.status !== AgentScopeRuntimeRunStatus.Failed && !((_res$output = _res.output) !== null && _res$output !== void 0 && (_res$output = _res$output[0]) !== null && _res$output !== void 0 && (_res$output = _res$output.content) !== null && _res$output !== void 0 && _res$output.length))) {
184
+ _context2.next = 35;
176
185
  break;
177
186
  }
178
- return _context2.abrupt("continue", 26);
179
- case 25:
187
+ return _context2.abrupt("continue", 36);
188
+ case 35:
180
189
  if (currentQARef.current.response) {
181
190
  currentQARef.current.response.cards = [{
182
191
  code: 'AgentScopeRuntimeResponseCard',
183
- data: res
192
+ data: _res
184
193
  }];
185
- if (res.status === AgentScopeRuntimeRunStatus.Completed || res.status === AgentScopeRuntimeRunStatus.Failed) {
194
+ if (_res.status === AgentScopeRuntimeRunStatus.Completed || _res.status === AgentScopeRuntimeRunStatus.Failed) {
186
195
  onFinish();
187
196
  } else {
188
197
  updateMessage(currentQARef.current.response);
189
198
  }
190
199
  }
191
- case 26:
200
+ case 36:
192
201
  _iteratorAbruptCompletion2 = false;
193
- _context2.next = 10;
202
+ _context2.next = 20;
194
203
  break;
195
- case 29:
196
- _context2.next = 35;
204
+ case 39:
205
+ _context2.next = 45;
197
206
  break;
198
- case 31:
199
- _context2.prev = 31;
200
- _context2.t0 = _context2["catch"](8);
207
+ case 41:
208
+ _context2.prev = 41;
209
+ _context2.t1 = _context2["catch"](18);
201
210
  _didIteratorError2 = true;
202
- _iteratorError2 = _context2.t0;
203
- case 35:
204
- _context2.prev = 35;
205
- _context2.prev = 36;
211
+ _iteratorError2 = _context2.t1;
212
+ case 45:
213
+ _context2.prev = 45;
214
+ _context2.prev = 46;
206
215
  if (!(_iteratorAbruptCompletion2 && _iterator2.return != null)) {
207
- _context2.next = 40;
216
+ _context2.next = 50;
208
217
  break;
209
218
  }
210
- _context2.next = 40;
219
+ _context2.next = 50;
211
220
  return _iterator2.return();
212
- case 40:
213
- _context2.prev = 40;
221
+ case 50:
222
+ _context2.prev = 50;
214
223
  if (!_didIteratorError2) {
215
- _context2.next = 43;
224
+ _context2.next = 53;
216
225
  break;
217
226
  }
218
227
  throw _iteratorError2;
219
- case 43:
220
- return _context2.finish(40);
221
- case 44:
222
- return _context2.finish(35);
223
- case 45:
224
- _context2.next = 50;
228
+ case 53:
229
+ return _context2.finish(50);
230
+ case 54:
231
+ return _context2.finish(45);
232
+ case 55:
233
+ _context2.next = 60;
225
234
  break;
226
- case 47:
227
- _context2.prev = 47;
228
- _context2.t1 = _context2["catch"](5);
229
- console.error(_context2.t1);
230
- case 50:
235
+ case 57:
236
+ _context2.prev = 57;
237
+ _context2.t2 = _context2["catch"](15);
238
+ console.error(_context2.t2);
239
+ case 60:
231
240
  case "end":
232
241
  return _context2.stop();
233
242
  }
234
- }, _callee2, null, [[5, 47], [8, 31, 35, 45], [36,, 40, 44]]);
243
+ }, _callee2, null, [[3, 11], [15, 57], [18, 41, 45, 55], [46,, 50, 54]]);
235
244
  }));
236
245
  return function (_x2) {
237
246
  return _ref2.apply(this, arguments);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentscope-ai/chat",
3
- "version": "1.1.58",
3
+ "version": "1.1.59",
4
4
  "description": "a free and open-source chat framework for building excellent LLM-powered chat experiences",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": [