jarvis-ai-assistant 0.1.213__py3-none-any.whl → 0.1.216__py3-none-any.whl

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.
@@ -180,7 +180,7 @@ def start_service(
180
180
  request: ChatCompletionRequest,
181
181
  ) -> Response:
182
182
  """Create a chat completion in OpenAI-compatible format.
183
-
183
+
184
184
  Returns:
185
185
  Response: Either a JSONResponse or StreamingResponse depending on the request.
186
186
  """
@@ -233,7 +233,7 @@ def start_service(
233
233
  if stream:
234
234
  # Return streaming response
235
235
  return StreamingResponse(
236
- stream_chat_response(platform, message_text, model),
236
+ stream_chat_response(platform, message_text, model), # type: ignore
237
237
  media_type="text/event-stream",
238
238
  )
239
239
 
@@ -258,36 +258,36 @@ def start_service(
258
258
  response_text,
259
259
  )
260
260
 
261
- return JSONResponse({
262
- "id": completion_id,
263
- "object": "chat.completion",
264
- "created": int(time.time()),
265
- "model": model,
266
- "choices": [
267
- {
268
- "index": 0,
269
- "message": {"role": "assistant", "content": response_text},
270
- "finish_reason": "stop",
271
- }
272
- ],
273
- "usage": {
274
- "prompt_tokens": len(message_text) // 4,
275
- "completion_tokens": len(response_text) // 4,
276
- "total_tokens": (len(message_text) + len(response_text)) // 4,
277
- },
278
- })
261
+ return JSONResponse(
262
+ {
263
+ "id": completion_id,
264
+ "object": "chat.completion",
265
+ "created": int(time.time()),
266
+ "model": model,
267
+ "choices": [
268
+ {
269
+ "index": 0,
270
+ "message": {"role": "assistant", "content": response_text},
271
+ "finish_reason": "stop",
272
+ }
273
+ ],
274
+ "usage": {
275
+ "prompt_tokens": len(message_text) // 4,
276
+ "completion_tokens": len(response_text) // 4,
277
+ "total_tokens": (len(message_text) + len(response_text)) // 4,
278
+ },
279
+ }
280
+ )
279
281
  except Exception as exc:
280
282
  raise HTTPException(status_code=500, detail=str(exc))
281
283
 
282
- async def stream_chat_response(
283
- platform: Any, message: str, model_name: str
284
- ) -> Any:
284
+ async def stream_chat_response(platform: Any, message: str, model_name: str) -> Any:
285
285
  """Stream chat response in OpenAI-compatible format."""
286
286
  completion_id = f"chatcmpl-{str(uuid.uuid4())}"
287
287
  created_time = int(time.time())
288
288
  conversation_id = str(uuid.uuid4())
289
289
 
290
- # Modify first yield statement format
290
+ # Send the initial chunk with the role
291
291
  initial_data = {
292
292
  "id": completion_id,
293
293
  "object": "chat.completion.chunk",
@@ -300,21 +300,17 @@ def start_service(
300
300
  yield f"data: {json.dumps(initial_data)}\n\n"
301
301
 
302
302
  try:
303
- # Get chat response directly
304
- response = platform.chat_until_success(message)
303
+ # Use the streaming-capable chat method
304
+ response_generator = platform.chat(message)
305
305
 
306
- # Record full response
307
306
  full_response = ""
307
+ has_content = False
308
308
 
309
- # If there is a response, send it in chunks
310
- if response:
311
- # Split into small chunks for better streaming experience
312
- chunk_size = 4
313
- for i in range(0, len(response), chunk_size):
314
- chunk = response[i : i + chunk_size]
309
+ # Iterate over the generator and stream chunks
310
+ for chunk in response_generator:
311
+ if chunk:
312
+ has_content = True
315
313
  full_response += chunk
316
-
317
- # Create and send chunk
318
314
  chunk_data = {
319
315
  "id": completion_id,
320
316
  "object": "chat.completion.chunk",
@@ -328,13 +324,10 @@ def start_service(
328
324
  }
329
325
  ],
330
326
  }
331
-
332
327
  yield f"data: {json.dumps(chunk_data)}\n\n"
333
328
 
334
- # Small delay to simulate streaming
335
- await asyncio.sleep(0.01)
336
- else:
337
- # If no output, send an empty content chunk
329
+ if not has_content:
330
+ no_response_message = "No response from model."
338
331
  chunk_data = {
339
332
  "id": completion_id,
340
333
  "object": "chat.completion.chunk",
@@ -343,15 +336,15 @@ def start_service(
343
336
  "choices": [
344
337
  {
345
338
  "index": 0,
346
- "delta": {"content": "No response from model."},
339
+ "delta": {"content": no_response_message},
347
340
  "finish_reason": None,
348
341
  }
349
342
  ],
350
343
  }
351
344
  yield f"data: {json.dumps(chunk_data)}\n\n"
352
- full_response = "No response from model."
345
+ full_response = no_response_message
353
346
 
354
- # Modify final yield statement format
347
+ # Send the final chunk with finish_reason
355
348
  final_data = {
356
349
  "id": completion_id,
357
350
  "object": "chat.completion.chunk",
@@ -361,72 +354,45 @@ def start_service(
361
354
  }
362
355
  yield f"data: {json.dumps(final_data)}\n\n"
363
356
 
364
- # Send [DONE] marker
357
+ # Send the [DONE] marker
365
358
  yield "data: [DONE]\n\n"
366
359
 
367
- # Log conversation to file
368
- timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
369
- log_file = os.path.join(
370
- logs_dir, f"stream_conversation_{conversation_id}_{timestamp}.json"
371
- )
372
-
373
- log_data = {
374
- "conversation_id": conversation_id,
375
- "timestamp": timestamp,
376
- "model": model_name,
377
- "message": message,
378
- "response": full_response,
379
- }
380
-
381
- with open(log_file, "w", encoding="utf-8", errors="ignore") as f:
382
- json.dump(log_data, f, ensure_ascii=False, indent=2)
383
-
384
- PrettyOutput.print(
385
- f"Stream conversation logged to {log_file}", OutputType.INFO
360
+ # Log the full conversation
361
+ log_conversation(
362
+ conversation_id,
363
+ [{"role": "user", "content": message}],
364
+ model_name,
365
+ full_response,
386
366
  )
387
367
 
388
368
  except Exception as exc:
389
- # Send error message
390
- error_msg = f"Error: {str(exc)}"
391
- print(f"Streaming error: {error_msg}")
369
+ error_msg = f"Error during streaming: {str(exc)}"
370
+ PrettyOutput.print(error_msg, OutputType.ERROR)
392
371
 
393
- res = json.dumps(
394
- {
395
- "id": completion_id,
396
- "object": "chat.completion.chunk",
397
- "created": created_time,
398
- "model": model_name,
399
- "choices": [
400
- {
401
- "index": 0,
402
- "delta": {"content": error_msg},
403
- "finish_reason": "stop",
404
- }
405
- ],
406
- }
407
- )
408
- yield f"data: {res}\n\n"
409
- yield f"data: {json.dumps({'error': {'message': error_msg, 'type': 'server_error'}})}\n\n"
410
- yield "data: [DONE]\n\n"
411
-
412
- # Log error to file
413
- timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
414
- log_file = os.path.join(
415
- logs_dir, f"stream_error_{conversation_id}_{timestamp}.json"
416
- )
417
-
418
- log_data = {
419
- "conversation_id": conversation_id,
420
- "timestamp": timestamp,
372
+ # Send error information in the stream
373
+ error_chunk = {
374
+ "id": completion_id,
375
+ "object": "chat.completion.chunk",
376
+ "created": created_time,
421
377
  "model": model_name,
422
- "message": message,
423
- "error": error_msg,
378
+ "choices": [
379
+ {
380
+ "index": 0,
381
+ "delta": {"content": error_msg},
382
+ "finish_reason": "stop",
383
+ }
384
+ ],
424
385
  }
386
+ yield f"data: {json.dumps(error_chunk)}\n\n"
387
+ yield "data: [DONE]\n\n"
425
388
 
426
- with open(log_file, "w", encoding="utf-8", errors="ignore") as f:
427
- json.dump(log_data, f, ensure_ascii=False, indent=2)
428
-
429
- PrettyOutput.print(f"Stream error logged to {log_file}", OutputType.ERROR)
389
+ # Log the error
390
+ log_conversation(
391
+ conversation_id,
392
+ [{"role": "user", "content": message}],
393
+ model_name,
394
+ response=f"ERROR: {error_msg}",
395
+ )
430
396
 
431
397
  # Run the server
432
398
  uvicorn.run(app, host=host, port=port)
@@ -109,6 +109,7 @@ class FileCompleter(Completer):
109
109
  (ot("Clear"), "清除历史"),
110
110
  (ot("ToolUsage"), "工具使用说明"),
111
111
  (ot("ReloadConfig"), "重新加载配置"),
112
+ (ot("SaveSession"), "保存当前会话"),
112
113
  ]
113
114
  )
114
115
 
@@ -222,10 +223,11 @@ def get_multiline_input(tip: str) -> str:
222
223
  if last_msg:
223
224
  try:
224
225
  # 使用xsel将内容复制到剪贴板
225
- process = subprocess.Popen(["xsel", "-b", "-i"], stdin=subprocess.PIPE)
226
- process.communicate(input=last_msg.encode("utf-8"))
226
+ subprocess.run(
227
+ ["xsel", "-b", "-i"], input=last_msg.encode("utf-8"), check=True
228
+ )
227
229
  PrettyOutput.print("已将最后一条消息复制到剪贴板", OutputType.INFO)
228
- except Exception as e:
230
+ except subprocess.CalledProcessError as e:
229
231
  PrettyOutput.print(f"复制到剪贴板失败: {e}", OutputType.ERROR)
230
232
  else:
231
233
  PrettyOutput.print("没有可复制的消息", OutputType.INFO)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.213
3
+ Version: 0.1.216
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire
@@ -1,13 +1,13 @@
1
- jarvis/__init__.py,sha256=-plSw2QooYexMaRlKIRHSdkQww5y9LDlUdoQ1gxFf2I,75
2
- jarvis/jarvis_agent/__init__.py,sha256=QbI5vkourPJZ2OR63RBZAtFptTYrZz_si8bIkc9EB2o,31709
3
- jarvis/jarvis_agent/builtin_input_handler.py,sha256=1V7kV5Zhw2HE3Xgjs1R-43RZ2huq3Kg-32NCdNnyZmA,2216
4
- jarvis/jarvis_agent/edit_file_handler.py,sha256=bIciBghx5maDz09x0XNTxdNsyrBbTND95GupVdJIVVg,16762
5
- jarvis/jarvis_agent/jarvis.py,sha256=tTv9X1oSRDGRmNkM1F3RNN6ikFbc_PkRBIbZIffbA_8,5802
1
+ jarvis/__init__.py,sha256=rTb7P5Us8MKb-Bgo5O9dZfaWM0pDjYYSSZCgb59Yois,75
2
+ jarvis/jarvis_agent/__init__.py,sha256=Ftod6FDMlGJ_DuueI2W19whAmpldVAsGYvlgbvqC55w,33260
3
+ jarvis/jarvis_agent/builtin_input_handler.py,sha256=lcw-VBm8-CVcblxEbGU4dVD6IixgXTLz9uBrv9Y6p20,2710
4
+ jarvis/jarvis_agent/edit_file_handler.py,sha256=vKx26I4yOQwiQHNfkqMJ44Ybf90n37mojTcXNQQy-hw,17382
5
+ jarvis/jarvis_agent/jarvis.py,sha256=4LBtAh9_AuQcjvqBFInqY19eyEJVJtGH4py32yu8olc,6287
6
6
  jarvis/jarvis_agent/main.py,sha256=c6bQe-8LXvW2-NBn9Rn_yPYdrwnkJ8KQaSFY2cPvkxw,2775
7
7
  jarvis/jarvis_agent/output_handler.py,sha256=P7oWpXBGFfOsWq7cIhS_z9crkQ19ES7qU5pM92KKjAs,1172
8
8
  jarvis/jarvis_agent/shell_input_handler.py,sha256=zVaKNthIHJh1j4g8_-d3w5ahNH9aH-ZNRSOourQpHR4,1328
9
9
  jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- jarvis/jarvis_code_agent/code_agent.py,sha256=x8CVDZstnRy2jemdnNN-avt1-wGntlSBD7qLlrk0qzU,17951
10
+ jarvis/jarvis_code_agent/code_agent.py,sha256=mQosGLngkM23sMAW9BJtl7XBPFmwOiIZUDG9tb7xAq8,18571
11
11
  jarvis/jarvis_code_agent/lint.py,sha256=LZPsfyZPMo7Wm7LN4osZocuNJwZx1ojacO3MlF870x8,4009
12
12
  jarvis/jarvis_code_analysis/code_review.py,sha256=uCCbGd4Y1RjDzhZoVE8JdN2avlwOfqimSDIrcM-KMew,30456
13
13
  jarvis/jarvis_code_analysis/checklists/__init__.py,sha256=LIXAYa1sW3l7foP6kohLWnE98I_EQ0T7z5bYKHq6rJA,78
@@ -45,18 +45,18 @@ jarvis/jarvis_methodology/main.py,sha256=-PqsWvtpUJkkhiGgV-1JegEnEZBmv8SHnNMNNm_
45
45
  jarvis/jarvis_multi_agent/__init__.py,sha256=sDd3sK88dS7_qAz2ywIAaEWdQ4iRVCiuBu2rQQmrKbU,4512
46
46
  jarvis/jarvis_multi_agent/main.py,sha256=h7VUSwoPrES0XTK8z5kt3XLX1mmcm8UEuFEHQOUWPH4,1696
47
47
  jarvis/jarvis_platform/__init__.py,sha256=WLQHSiE87PPket2M50_hHzjdMIgPIBx2VF8JfB_NNRk,105
48
- jarvis/jarvis_platform/ai8.py,sha256=UWbe6kveQvOO8wMM9mh5YWyB0zapUEeFiYVPBMnhBAE,8845
49
- jarvis/jarvis_platform/base.py,sha256=CBFk1Kq7qzOwafOj22bacXChWvCnap3D4IacZCWC_Ss,7882
50
- jarvis/jarvis_platform/human.py,sha256=_WQtC5w6QJnHh-3KuW8T49C-HucXiHsBEVw-m51ykj4,3196
51
- jarvis/jarvis_platform/kimi.py,sha256=w0-OJ6xkOGPApcc2Jvc30BMjabwrnzcndmsJJsWOWJg,13419
52
- jarvis/jarvis_platform/openai.py,sha256=uEjBikfFj7kp5wondLvOx4WdkmTX0aqF6kixxAufcHg,4806
53
- jarvis/jarvis_platform/oyi.py,sha256=U6klSMESC69H9xTo44PXD1ZvdnMa5d7qE3jcPmPBspY,10662
54
- jarvis/jarvis_platform/registry.py,sha256=Sz4ADAaxuufpAQG0KSQZuL1yALzH-aF3FDapkNn5foE,8107
55
- jarvis/jarvis_platform/tongyi.py,sha256=juvzMjZ2mbNzSWzem8snmFuE28YVOjjE_YdHCZa9Qnw,20698
56
- jarvis/jarvis_platform/yuanbao.py,sha256=ZsKXWifESXGfvB9eOot1I6TnhlmgXwnaft3e2UXgSXk,21045
48
+ jarvis/jarvis_platform/ai8.py,sha256=yi7xG8ld4Yrf7drz-uu_JT_XCGYRB0obhygt-jKik8o,10871
49
+ jarvis/jarvis_platform/base.py,sha256=-XegiAS8G_nzwsWPOVEAQ2iTxE33fxu5-TWV4c3Pz-g,8981
50
+ jarvis/jarvis_platform/human.py,sha256=quB5yMMoyU8w55IrVqa9F4ITOpF2TdM0GHQVD9zyWgk,4925
51
+ jarvis/jarvis_platform/kimi.py,sha256=OEiRNlC4Ao3PrO_yiogEwgMtTobehoEm_X4CMGT-Aas,15315
52
+ jarvis/jarvis_platform/openai.py,sha256=ccGqsU2cFfd5324P7SH1tSmFABpvto8fytmxQGkr3BA,6412
53
+ jarvis/jarvis_platform/oyi.py,sha256=GvVooV8ScRqDb9QxJdINtdZwsx6PUIdo1-bt9k0hmqY,12604
54
+ jarvis/jarvis_platform/registry.py,sha256=1bMy0YZUa8NLzuZlKfC4CBtpa0iniypTxUZk0Hv6g9Y,8415
55
+ jarvis/jarvis_platform/tongyi.py,sha256=vSK1b4NhTeHbNhTgGRj4PANXptwCAwitczwK8VXwWwU,22921
56
+ jarvis/jarvis_platform/yuanbao.py,sha256=W4yEsjkxnwi681UnAX0hV8vVPuNRmn6lRGZ3G-d74nw,23007
57
57
  jarvis/jarvis_platform_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- jarvis/jarvis_platform_manager/main.py,sha256=tIb3jUuMF0ErislPjo8TkEUqL04snfEJwMPSZiOkMmY,15659
59
- jarvis/jarvis_platform_manager/service.py,sha256=rY1FmNl-tmbkkke_3SlH9h6ckyPIgmSwbaRorURp9Cc,14916
58
+ jarvis/jarvis_platform_manager/main.py,sha256=LxlXSfIfmkYNcajOG_XvvlmwlSWSGb0DmbzIDSHHYOU,18330
59
+ jarvis/jarvis_platform_manager/service.py,sha256=hQGWQ2qAlzm_C_lNQDuLORQ4rmjR1P1-V3ou7l2Bv0s,13622
60
60
  jarvis/jarvis_smart_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
61
  jarvis/jarvis_smart_shell/main.py,sha256=DbhRSP1sZfSIaTltP1YWVDSQOTYEsbiOnfO9kSYwcNs,6959
62
62
  jarvis/jarvis_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -83,14 +83,14 @@ jarvis/jarvis_utils/file_processors.py,sha256=XiM248SHS7lLgQDCbORVFWqinbVDUawYxW
83
83
  jarvis/jarvis_utils/git_utils.py,sha256=7AZblSD4b76vXxaDFkmZOy5rNkwvkwQQxGUy3NAusDQ,21641
84
84
  jarvis/jarvis_utils/globals.py,sha256=WzZh_acNfHJj1LDulhyLQ7cojksBy0gdrITe0vH1XA0,3901
85
85
  jarvis/jarvis_utils/http.py,sha256=Uqt1kcz0HWnAfXHHi1fNGwLb2lcVUqpbrG2Uk_-kcIU,4882
86
- jarvis/jarvis_utils/input.py,sha256=D0fQ6sRHjBaMm8s1L8HccC09Qlt_JD_SB_EHPCoztyA,8907
86
+ jarvis/jarvis_utils/input.py,sha256=XNnSOY7EEcqxA2DZcCQ40l0q30b1Lu7ijbfKjq6WWCA,8965
87
87
  jarvis/jarvis_utils/methodology.py,sha256=-cvM6pwgJK7BXCYg2uVjIId_j3v5RUh2z2PBcK_2vj4,8155
88
88
  jarvis/jarvis_utils/output.py,sha256=PRCgudPOB8gMEP3u-g0FGD2c6tBgJhLXUMqNPglfjV8,10813
89
89
  jarvis/jarvis_utils/tag.py,sha256=f211opbbbTcSyzCDwuIK_oCnKhXPNK-RknYyGzY1yD0,431
90
90
  jarvis/jarvis_utils/utils.py,sha256=BoRwLcixdf7mU3Tawe95ygGhQpkMffrFYLYhPwIvw8A,14498
91
- jarvis_ai_assistant-0.1.213.dist-info/licenses/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
92
- jarvis_ai_assistant-0.1.213.dist-info/METADATA,sha256=ihUbPrOcnHuEjAtbY2-IA3Tj_ZOM3Hj_YDT5wJcsH6M,19564
93
- jarvis_ai_assistant-0.1.213.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
94
- jarvis_ai_assistant-0.1.213.dist-info/entry_points.txt,sha256=SF46ViTZcQVZEfbqzJDKKVc9TrN1x-P1mQ6wup7u2HY,875
95
- jarvis_ai_assistant-0.1.213.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
96
- jarvis_ai_assistant-0.1.213.dist-info/RECORD,,
91
+ jarvis_ai_assistant-0.1.216.dist-info/licenses/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
92
+ jarvis_ai_assistant-0.1.216.dist-info/METADATA,sha256=h2xfZU2lBL5kVLTBDEXchXrSf5iOo19QISqjp1E2V64,19564
93
+ jarvis_ai_assistant-0.1.216.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
94
+ jarvis_ai_assistant-0.1.216.dist-info/entry_points.txt,sha256=SF46ViTZcQVZEfbqzJDKKVc9TrN1x-P1mQ6wup7u2HY,875
95
+ jarvis_ai_assistant-0.1.216.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
96
+ jarvis_ai_assistant-0.1.216.dist-info/RECORD,,