@josephyan/qingflow-app-builder-mcp 0.2.0-beta.98 → 0.2.0-beta.981

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/README.md CHANGED
@@ -3,13 +3,13 @@
3
3
  Install:
4
4
 
5
5
  ```bash
6
- npm install @josephyan/qingflow-app-builder-mcp@0.2.0-beta.98
6
+ npm install @josephyan/qingflow-app-builder-mcp@0.2.0-beta.981
7
7
  ```
8
8
 
9
9
  Run:
10
10
 
11
11
  ```bash
12
- npx -y -p @josephyan/qingflow-app-builder-mcp@0.2.0-beta.98 qingflow-app-builder-mcp
12
+ npx -y -p @josephyan/qingflow-app-builder-mcp@0.2.0-beta.981 qingflow-app-builder-mcp
13
13
  ```
14
14
 
15
15
  Environment:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@josephyan/qingflow-app-builder-mcp",
3
- "version": "0.2.0-beta.98",
3
+ "version": "0.2.0-beta.981",
4
4
  "description": "Builder MCP for Qingflow app/package/system design and staged solution workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qingflow-mcp"
7
- version = "0.2.0b98"
7
+ version = "0.2.0b981"
8
8
  description = "User-authenticated MCP server for Qingflow"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -5,7 +5,7 @@ from pathlib import Path
5
5
 
6
6
  __all__ = ["__version__"]
7
7
 
8
- _FALLBACK_VERSION = "0.2.0b97"
8
+ _FALLBACK_VERSION = "0.2.0b981"
9
9
 
10
10
 
11
11
  def _resolve_local_pyproject_version() -> str | None:
@@ -177,10 +177,10 @@ def _format_task_list(result: dict[str, Any]) -> str:
177
177
  str(item.get("app_key") or ""),
178
178
  str(item.get("record_id") or ""),
179
179
  str(item.get("workflow_node_id") or ""),
180
- str(item.get("title") or item.get("task_name") or ""),
180
+ str(item.get("workflow_node_name") or ""),
181
181
  ]
182
182
  )
183
- output = _render_titled_table("Tasks", ["app_key", "record_id", "node_id", "title"], rows)
183
+ output = _render_titled_table("Tasks", ["app_key", "record_id", "node_id", "node_name"], rows)
184
184
  lines = output.rstrip("\n").split("\n")
185
185
  _append_warnings(lines, result.get("warnings"))
186
186
  return "\n".join(lines) + "\n"
@@ -193,11 +193,13 @@ def _format_task_get(result: dict[str, Any]) -> str:
193
193
  editable_fields = data.get("editable_fields") if isinstance(data.get("editable_fields"), list) else []
194
194
  available_actions = data.get("available_actions") if isinstance(data.get("available_actions"), list) else []
195
195
  extras = data.get("extras") if isinstance(data.get("extras"), dict) else {}
196
+ initiator = task.get("initiator") if isinstance(task.get("initiator"), dict) else {}
197
+ initiator_label = initiator.get("displayName") or initiator.get("email") or "-"
196
198
  lines = [
197
199
  f"Task: {task.get('app_key') or '-'} / {task.get('record_id') or '-'} / {task.get('workflow_node_id') or '-'}",
198
200
  f"Node: {task.get('workflow_node_name') or '-'}",
199
201
  f"App: {task.get('app_name') or '-'}",
200
- f"Initiator: {task.get('initiator') or '-'}",
202
+ f"Initiator: {initiator_label}",
201
203
  f"Apply Status: {record_summary.get('apply_status')}",
202
204
  f"Available Actions: {', '.join(str(item) for item in available_actions) or '-'}",
203
205
  f"Editable Fields: {len(editable_fields)}",
@@ -238,17 +240,22 @@ def _format_import_verify(result: dict[str, Any]) -> str:
238
240
  f"App Key: {result.get('app_key') or '-'}",
239
241
  f"File: {result.get('file_name') or result.get('file_path') or '-'}",
240
242
  f"Can Import: {result.get('can_import')}",
241
- f"Apply Rows: {result.get('apply_rows')}",
242
243
  f"Verification ID: {result.get('verification_id') or '-'}",
243
244
  ]
244
- issues = result.get("issues") if isinstance(result.get("issues"), list) else []
245
- if issues:
246
- lines.append("Issues:")
247
- for issue in issues:
248
- if isinstance(issue, dict):
249
- lines.append(f"- {issue.get('code') or 'ISSUE'}: {issue.get('message') or issue}")
250
- else:
251
- lines.append(f"- {issue}")
245
+ issue_summary = result.get("issue_summary") if isinstance(result.get("issue_summary"), dict) else {}
246
+ if issue_summary:
247
+ lines.append(
248
+ "Issues: "
249
+ f"total={issue_summary.get('total', 0)}, "
250
+ f"errors={issue_summary.get('errors', 0)}, "
251
+ f"warnings={issue_summary.get('warnings', 0)}"
252
+ )
253
+ sample = issue_summary.get("sample") if isinstance(issue_summary.get("sample"), list) else []
254
+ if sample:
255
+ lines.append("Issue Samples:")
256
+ for item in sample:
257
+ if isinstance(item, dict):
258
+ lines.append(f"- {item.get('code') or 'ISSUE'}: {item.get('message') or ''}".rstrip())
252
259
  _append_warnings(lines, result.get("warnings"))
253
260
  _append_verification(lines, result.get("verification"))
254
261
  return "\n".join(lines) + "\n"
@@ -259,8 +266,9 @@ def _format_import_status(result: dict[str, Any]) -> str:
259
266
  f"Status: {result.get('status') or '-'}",
260
267
  f"Import ID: {result.get('import_id') or '-'}",
261
268
  f"Process ID: {result.get('process_id_str') or '-'}",
262
- f"Success Rows: {result.get('success_rows') or 0}",
263
- f"Failed Rows: {result.get('failed_rows') or 0}",
269
+ f"Total Rows: {result.get('total') or 0}",
270
+ f"Finished Rows: {result.get('finished') or 0}",
271
+ f"Failed Rows: {result.get('failed') or 0}",
264
272
  f"Progress: {result.get('progress') or '-'}",
265
273
  ]
266
274
  _append_warnings(lines, result.get("warnings"))
@@ -293,34 +293,150 @@ def _trim_file_upload_local(payload: JSONObject) -> None:
293
293
 
294
294
 
295
295
  def _trim_import_schema(payload: JSONObject) -> None:
296
- pass
296
+ columns: list[JSONObject] | None = None
297
+ if isinstance(payload.get("columns"), list):
298
+ columns = [item for item in payload.get("columns", []) if isinstance(item, dict)]
299
+ elif isinstance(payload.get("expected_columns"), list):
300
+ columns = [item for item in payload.get("expected_columns", []) if isinstance(item, dict)]
301
+ if columns is not None:
302
+ payload["columns"] = [_compact_import_column(item) for item in columns]
303
+ payload.pop("expected_columns", None)
304
+ payload.pop("schema_fingerprint", None)
305
+ payload.pop("import_capability", None)
306
+ payload.pop("request_route", None)
307
+ payload.pop("verification", None)
308
+
309
+ if _looks_like_import_verify(payload):
310
+ _trim_import_verify_payload(payload)
311
+ return
312
+ if "applied_repairs" in payload or "repaired_file_path" in payload:
313
+ _trim_import_repair_payload(payload)
314
+ return
315
+ if "template_url" in payload or "downloaded_to_path" in payload:
316
+ _trim_import_template_payload(payload)
317
+ return
318
+ if "import_id" in payload or "process_id_str" in payload:
319
+ _trim_import_status_payload(payload)
320
+ return
297
321
 
298
322
 
299
323
  def _trim_record_schema(payload: JSONObject) -> None:
300
324
  payload.pop("legacy_schema", None)
325
+ template_map = payload.get("payload_template")
326
+ if not isinstance(template_map, dict):
327
+ template_map = None
328
+
329
+ if "writable_fields" in payload:
330
+ writable_fields = payload.get("writable_fields")
331
+ payload.pop("writable_fields", None)
332
+ required_fields: list[JSONObject] = []
333
+ optional_fields: list[JSONObject] = []
334
+ if isinstance(writable_fields, list):
335
+ for item in writable_fields:
336
+ compact = _compact_schema_field(item, template_map=template_map)
337
+ if not compact:
338
+ continue
339
+ if compact.get("required") is True:
340
+ required_fields.append(compact)
341
+ else:
342
+ optional_fields.append(compact)
343
+ payload["required_fields"] = required_fields
344
+ payload["optional_fields"] = optional_fields
345
+
346
+ for key in ("required_fields", "optional_fields", "runtime_linked_required_fields", "fields"):
347
+ if key in payload:
348
+ payload[key] = _compact_schema_fields(payload.get(key), template_map=template_map)
349
+
350
+ for key in ("suggested_dimensions", "suggested_metrics", "suggested_time_fields"):
351
+ if isinstance(payload.get(key), list):
352
+ payload[key] = [
353
+ _pick(item, ("field_id", "title")) for item in payload.get(key) if isinstance(item, dict)
354
+ ]
355
+
356
+ for key in ("workflow_node", "view_resolution", "field_count", "record_context_probe", "view_probe_summary", "ambiguous_fields"):
357
+ payload.pop(key, None)
301
358
 
302
359
 
303
360
  def _trim_record_write(payload: JSONObject) -> None:
304
361
  data = payload.get("data")
305
362
  if not isinstance(data, dict):
306
363
  return
364
+ data.pop("debug", None)
307
365
  data.pop("normalized_payload", None)
308
366
  data.pop("human_review", None)
309
367
  data.pop("action", None)
368
+ resource = _compact_record_resource(data.get("resource"))
369
+ if resource:
370
+ data["resource"] = resource
371
+ else:
372
+ data.pop("resource", None)
310
373
 
311
374
 
312
375
  def _trim_record_get(payload: JSONObject) -> None:
313
- _keep_nested_keys(payload, ("data", "selection", "view"), allowed=("view_id", "name"))
314
- _drop_nested_keys(payload, ("data", "selection"), keys=("columns", "workflow_node_id"))
376
+ data = payload.get("data")
377
+ if not isinstance(data, dict):
378
+ return
379
+ compact: dict[str, Any] = {}
380
+ app_key = data.get("app_key")
381
+ if app_key:
382
+ compact["app_key"] = app_key
383
+ record_id = data.get("record_id")
384
+ if record_id not in (None, ""):
385
+ compact["record_id"] = str(record_id)
386
+ record = data.get("record")
387
+ if isinstance(record, dict):
388
+ compact["record"] = record
389
+ payload["data"] = compact
315
390
 
316
391
 
317
392
  def _trim_record_list(payload: JSONObject) -> None:
318
- _keep_nested_keys(payload, ("data", "selection", "view"), allowed=("view_id", "name"))
319
- _drop_nested_keys(payload, ("data", "selection"), keys=("columns",))
393
+ data = payload.get("data")
394
+ if not isinstance(data, dict):
395
+ return
396
+ pagination = data.get("pagination") if isinstance(data.get("pagination"), dict) else {}
397
+ returned_items = pagination.get("returned_items")
398
+ result_amount = pagination.get("result_amount")
399
+ limit = pagination.get("limit")
400
+ truncated = False
401
+ if isinstance(result_amount, int) and isinstance(returned_items, int):
402
+ truncated = result_amount > returned_items
403
+ compact_pagination = {
404
+ "loaded": True,
405
+ "page_size": limit,
406
+ "fetched_pages": 1,
407
+ "reported_total": result_amount,
408
+ "truncated": truncated,
409
+ }
410
+ selection = data.get("selection") if isinstance(data.get("selection"), dict) else {}
411
+ view = selection.get("view") if isinstance(selection.get("view"), dict) else {}
412
+ compact: dict[str, Any] = {
413
+ "app_key": data.get("app_key"),
414
+ "items": data.get("items") if isinstance(data.get("items"), list) else [],
415
+ "pagination": compact_pagination,
416
+ }
417
+ if view:
418
+ compact["view"] = _pick(view, ("view_id", "name"))
419
+ payload["data"] = compact
320
420
 
321
421
 
322
422
  def _trim_record_analyze(payload: JSONObject) -> None:
323
- _drop_deep_keys(payload, {"debug"})
423
+ summary: dict[str, Any] = {}
424
+ completeness = payload.get("completeness")
425
+ if isinstance(completeness, dict):
426
+ summary["completeness"] = completeness
427
+ presentation = payload.get("presentation")
428
+ if isinstance(presentation, dict):
429
+ summary["presentation"] = presentation
430
+ ranking = payload.get("ranking")
431
+ if isinstance(ranking, dict):
432
+ summary["ranking"] = ranking
433
+ error = payload.get("error")
434
+ if isinstance(error, dict):
435
+ summary["error"] = error
436
+ if summary:
437
+ payload["summary"] = summary
438
+ for key in ("query", "ranking", "ratios", "completeness", "presentation", "error", "debug"):
439
+ payload.pop(key, None)
324
440
 
325
441
 
326
442
  def _trim_code_block_schema(payload: JSONObject) -> None:
@@ -344,6 +460,207 @@ def _trim_task_context_detail(payload: JSONObject) -> None:
344
460
  _drop_deep_keys(payload, {"request_route", "output_profile"})
345
461
 
346
462
 
463
+ def _trim_record_delete(payload: JSONObject) -> None:
464
+ data = payload.get("data")
465
+ if not isinstance(data, dict):
466
+ return
467
+ resource = data.get("resource")
468
+ deleted_ids: list[str] = []
469
+ if isinstance(resource, dict):
470
+ raw_ids = resource.get("record_ids") or resource.get("apply_ids") or resource.get("applyIds")
471
+ if isinstance(raw_ids, list):
472
+ deleted_ids = [str(item) for item in raw_ids if item not in (None, "")]
473
+ data["deleted_ids"] = deleted_ids
474
+ data.setdefault("failed_ids", [])
475
+ for key in (
476
+ "resource",
477
+ "action",
478
+ "normalized_payload",
479
+ "human_review",
480
+ "verification",
481
+ "blockers",
482
+ "field_errors",
483
+ "confirmation_requests",
484
+ "resolved_fields",
485
+ "debug",
486
+ ):
487
+ data.pop(key, None)
488
+
489
+
490
+ def _compact_record_resource(resource: Any) -> dict[str, Any] | None:
491
+ if not isinstance(resource, dict):
492
+ return None
493
+ compact: dict[str, Any] = {}
494
+ if resource.get("type") not in (None, ""):
495
+ compact["type"] = resource.get("type")
496
+ app_key = resource.get("app_key") or resource.get("appKey")
497
+ if app_key not in (None, ""):
498
+ compact["app_key"] = app_key
499
+ record_id = resource.get("record_id")
500
+ if record_id not in (None, ""):
501
+ compact["record_id"] = str(record_id)
502
+ apply_id = resource.get("apply_id") or resource.get("applyId")
503
+ if apply_id not in (None, "") and "record_id" not in compact:
504
+ compact["record_id"] = str(apply_id)
505
+ record_ids = resource.get("record_ids")
506
+ if isinstance(record_ids, list):
507
+ compact["record_ids"] = [str(item) for item in record_ids if item not in (None, "")]
508
+ apply_ids = resource.get("apply_ids") or resource.get("applyIds")
509
+ if isinstance(apply_ids, list) and "record_ids" not in compact:
510
+ compact["record_ids"] = [str(item) for item in apply_ids if item not in (None, "")]
511
+ return compact or None
512
+
513
+
514
+ def _compact_schema_fields(items: Any, *, template_map: dict[str, Any] | None) -> list[JSONObject]:
515
+ if not isinstance(items, list):
516
+ return []
517
+ compacted: list[JSONObject] = []
518
+ for item in items:
519
+ compact = _compact_schema_field(item, template_map=template_map)
520
+ if compact:
521
+ compacted.append(compact)
522
+ return compacted
523
+
524
+
525
+ def _compact_schema_field(item: Any, *, template_map: dict[str, Any] | None) -> JSONObject | None:
526
+ if not isinstance(item, dict):
527
+ return None
528
+ compact: dict[str, Any] = {}
529
+ field_id = item.get("field_id")
530
+ if field_id not in (None, ""):
531
+ compact["field_id"] = field_id
532
+ title = item.get("title")
533
+ if title not in (None, ""):
534
+ compact["title"] = title
535
+ kind = item.get("kind") or item.get("write_kind")
536
+ if kind not in (None, ""):
537
+ compact["kind"] = kind
538
+ if "required" in item:
539
+ compact["required"] = bool(item.get("required"))
540
+ if template_map is not None and isinstance(title, str) and title in template_map:
541
+ compact["template"] = template_map.get(title)
542
+ candidate_hint = item.get("candidate_hint")
543
+ if isinstance(candidate_hint, dict):
544
+ compact["candidate_hint"] = candidate_hint
545
+ options = item.get("options")
546
+ if isinstance(options, list) and options:
547
+ compact["options"] = options
548
+ target_app_key = item.get("target_app_key")
549
+ if isinstance(target_app_key, str) and target_app_key:
550
+ compact["target_app_key"] = target_app_key
551
+ searchable_fields = item.get("searchable_fields")
552
+ if isinstance(searchable_fields, list) and searchable_fields:
553
+ compact["searchable_fields"] = searchable_fields
554
+ row_fields = item.get("row_fields")
555
+ if isinstance(row_fields, list) and row_fields:
556
+ compact["row_fields"] = _compact_schema_fields(row_fields, template_map=None)
557
+ return compact or None
558
+
559
+
560
+ def _compact_import_column(item: dict[str, Any]) -> dict[str, Any]:
561
+ compact: dict[str, Any] = {
562
+ "title": item.get("title"),
563
+ "kind": item.get("kind") or item.get("write_kind"),
564
+ "required": bool(item.get("required")),
565
+ }
566
+ options = item.get("options")
567
+ if isinstance(options, list) and options:
568
+ compact["options"] = options
569
+ if bool(item.get("accepts_natural_input")):
570
+ compact["accepts_natural_input"] = True
571
+ if bool(item.get("requires_upload")):
572
+ compact["requires_upload"] = True
573
+ target_app_key = item.get("target_app_key")
574
+ if isinstance(target_app_key, str) and target_app_key:
575
+ compact["target_app_key"] = target_app_key
576
+ target_app_name = item.get("target_app_name")
577
+ if isinstance(target_app_name, str) and target_app_name:
578
+ compact["target_app_name"] = target_app_name
579
+ searchable_fields = item.get("searchable_fields")
580
+ if isinstance(searchable_fields, list) and searchable_fields:
581
+ compact["searchable_fields"] = searchable_fields
582
+ return compact
583
+
584
+
585
+ def _looks_like_import_verify(payload: JSONObject) -> bool:
586
+ return "verification_id" in payload and "can_import" in payload
587
+
588
+
589
+ def _trim_import_verify_payload(payload: JSONObject) -> None:
590
+ issues = payload.get("issues") if isinstance(payload.get("issues"), list) else []
591
+ issue_summary = _summarize_import_issues(issues)
592
+ payload["issue_summary"] = issue_summary
593
+ file_name = payload.get("file_name")
594
+ if not file_name:
595
+ file_path = payload.get("file_path")
596
+ if isinstance(file_path, str) and file_path:
597
+ payload["file_name"] = file_path.split("/")[-1]
598
+ for key in ("issues", "apply_rows", "expected_columns", "schema_fingerprint", "import_capability", "file_path", "file_sha256", "verified_file_sha256", "file_format", "auto_normalized", "local_precheck_limited"):
599
+ payload.pop(key, None)
600
+
601
+
602
+ def _trim_import_repair_payload(payload: JSONObject) -> None:
603
+ payload["verification_id"] = payload.get("new_verification_id") or payload.get("verification_id")
604
+ for key in ("new_verification_id", "source_file_path", "repaired_file_path", "post_repair_issues", "verification"):
605
+ payload.pop(key, None)
606
+
607
+
608
+ def _trim_import_template_payload(payload: JSONObject) -> None:
609
+ for key in ("schema_fingerprint", "verification"):
610
+ payload.pop(key, None)
611
+
612
+
613
+ def _trim_import_status_payload(payload: JSONObject) -> None:
614
+ total_rows = payload.get("total_rows")
615
+ success_rows = payload.get("success_rows")
616
+ failed_rows = payload.get("failed_rows")
617
+ payload["total"] = total_rows
618
+ payload["finished"] = success_rows
619
+ payload["failed"] = failed_rows
620
+ for key in (
621
+ "matched_by",
622
+ "source_file_name",
623
+ "total_rows",
624
+ "success_rows",
625
+ "failed_rows",
626
+ "error_file_urls",
627
+ "operate_time",
628
+ "operate_user",
629
+ "verification",
630
+ ):
631
+ payload.pop(key, None)
632
+
633
+
634
+ def _summarize_import_issues(issues: list[Any]) -> dict[str, Any]:
635
+ total = 0
636
+ error_count = 0
637
+ warning_count = 0
638
+ sample: list[dict[str, Any]] = []
639
+ for item in issues:
640
+ if not isinstance(item, dict):
641
+ continue
642
+ total += 1
643
+ severity = str(item.get("severity") or "").lower()
644
+ if severity == "error":
645
+ error_count += 1
646
+ if severity == "warning":
647
+ warning_count += 1
648
+ if len(sample) < 3:
649
+ sample.append(
650
+ {
651
+ "code": item.get("code"),
652
+ "message": item.get("message"),
653
+ "severity": item.get("severity"),
654
+ }
655
+ )
656
+ return {
657
+ "total": total,
658
+ "errors": error_count,
659
+ "warnings": warning_count,
660
+ "sample": sample,
661
+ }
662
+
663
+
347
664
  def _trim_directory(payload: JSONObject) -> None:
348
665
  pass
349
666
 
@@ -442,10 +759,10 @@ _register_policy(
442
759
  (
443
760
  "record_member_candidates",
444
761
  "record_department_candidates",
445
- "record_delete",
446
762
  ),
447
763
  _trim_builder_list_like,
448
764
  )
765
+ _register_policy((USER_DOMAIN,), ("record_delete",), _trim_record_delete)
449
766
  _register_policy(
450
767
  (BUILDER_DOMAIN,),
451
768
  (
@@ -1025,6 +1025,7 @@ class RecordTools(ToolBase):
1025
1025
  else:
1026
1026
  required = bool(required_override) if required_override is not None else bool(field.required)
1027
1027
  payload: JSONObject = {
1028
+ "field_id": field.que_id,
1028
1029
  "title": field.que_title,
1029
1030
  "kind": kind,
1030
1031
  "required": required,
@@ -1371,7 +1371,7 @@ class TaskContextTools(ToolBase):
1371
1371
  "record_id": task.get("record_id"),
1372
1372
  "workflow_node_id": task.get("workflow_node_id"),
1373
1373
  "workflow_node_name": task.get("workflow_node_name"),
1374
- "initiator": record.get("apply_user"),
1374
+ "initiator": self._compact_initiator(record.get("apply_user")),
1375
1375
  "actionable": task.get("actionable"),
1376
1376
  },
1377
1377
  "record_summary": {
@@ -1416,12 +1416,6 @@ class TaskContextTools(ToolBase):
1416
1416
  },
1417
1417
  },
1418
1418
  }
1419
- action_metadata = self._compact_task_action_metadata(capabilities)
1420
- if action_metadata:
1421
- compact["action_metadata"] = action_metadata
1422
- editable_metadata = self._compact_task_editable_metadata(update_schema)
1423
- if editable_metadata:
1424
- compact["editable_metadata"] = editable_metadata
1425
1419
  return compact
1426
1420
 
1427
1421
  def _compact_task_action_metadata(self, capabilities: dict[str, Any]) -> dict[str, Any]:
@@ -1449,6 +1443,18 @@ class TaskContextTools(ToolBase):
1449
1443
  metadata["warnings"] = warnings
1450
1444
  return metadata
1451
1445
 
1446
+ def _compact_initiator(self, payload: Any) -> dict[str, Any] | None:
1447
+ if not isinstance(payload, dict):
1448
+ return None
1449
+ compact = {
1450
+ "uid": payload.get("uid"),
1451
+ "displayName": payload.get("displayName") or payload.get("name") or payload.get("nickName"),
1452
+ "email": payload.get("email"),
1453
+ "mobile": payload.get("mobile"),
1454
+ "headImg": payload.get("headImg"),
1455
+ }
1456
+ return {key: value for key, value in compact.items() if value not in (None, "", [])} or None
1457
+
1452
1458
  def _task_app_name(self, detail: dict[str, Any], node_info: dict[str, Any]) -> Any:
1453
1459
  for source in (detail, node_info):
1454
1460
  for key in ("formTitle", "appName", "worksheetName", "appTitle"):
@@ -1550,12 +1556,6 @@ class TaskContextTools(ToolBase):
1550
1556
  app_key = raw.get("appKey") or raw.get("app_key")
1551
1557
  record_id = raw.get("rowRecordId") or raw.get("recordId") or raw.get("applyId")
1552
1558
  workflow_node_id = raw.get("nodeId") or raw.get("auditNodeId")
1553
- apply_user = raw.get("applyUser")
1554
- if apply_user is None:
1555
- user_uid = raw.get("applyUserUid")
1556
- user_name = raw.get("applyUserName")
1557
- if user_uid is not None or user_name is not None:
1558
- apply_user = {"uid": user_uid, "name": user_name}
1559
1559
  return {
1560
1560
  "task_id": raw.get("id") or raw.get("taskId") or record_id,
1561
1561
  "app_key": app_key,
@@ -1563,8 +1563,6 @@ class TaskContextTools(ToolBase):
1563
1563
  "record_id": record_id,
1564
1564
  "workflow_node_id": workflow_node_id,
1565
1565
  "workflow_node_name": raw.get("nodeName") or raw.get("auditNodeName"),
1566
- "title": raw.get("title") or raw.get("applyTitle") or raw.get("name") or raw.get("formTitle"),
1567
- "apply_user": apply_user,
1568
1566
  "apply_time": raw.get("applyTime") or raw.get("receiveTime"),
1569
1567
  "task_box": task_box,
1570
1568
  "flow_status": flow_status,