@tasksai/install 0.1.27 → 0.1.29
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/package.json +1 -1
- package/runtime/server.py +87 -5
package/package.json
CHANGED
package/runtime/server.py
CHANGED
|
@@ -125,7 +125,7 @@ if not LICENSE_KEY:
|
|
|
125
125
|
print("Find your key in your purchase confirmation email.", file=sys.stderr, flush=True)
|
|
126
126
|
sys.exit(1)
|
|
127
127
|
|
|
128
|
-
SERVER_VERSION = "2.4.
|
|
128
|
+
SERVER_VERSION = "2.4.5"
|
|
129
129
|
|
|
130
130
|
AUTH_HEADERS = {
|
|
131
131
|
"Authorization": f"Bearer {LICENSE_KEY}",
|
|
@@ -962,7 +962,7 @@ def iter_inline_markdown(text):
|
|
|
962
962
|
"""Yield (text, marks) spans for common inline Markdown."""
|
|
963
963
|
text = re.sub(r"\\([\\`*_{}\[\]()#+.!-])", r"\1", text)
|
|
964
964
|
token_re = re.compile(
|
|
965
|
-
r"(`[^`]+`|\*\*[^*]+\*\*|__[^_]
|
|
965
|
+
r"(`[^`]+`|\*\*[^*]+\*\*|(?<!_)__(?![_\s])[^_]+?(?<!\s)__(?!_)|\*[^*\s][^*]*\*|(?<!\w)_[^_\s][^_]*_(?!\w)|\[[^\]]+\]\([^)]+\))"
|
|
966
966
|
)
|
|
967
967
|
pos = 0
|
|
968
968
|
for match in token_re.finditer(text):
|
|
@@ -1052,6 +1052,14 @@ def add_markdown_text(paragraph, text):
|
|
|
1052
1052
|
run.font.name = "Courier New"
|
|
1053
1053
|
|
|
1054
1054
|
|
|
1055
|
+
def add_markdown_heading(doc, text, level):
|
|
1056
|
+
"""Create a Word heading while parsing any inline Markdown in its text."""
|
|
1057
|
+
|
|
1058
|
+
paragraph = doc.add_heading(level=level)
|
|
1059
|
+
add_markdown_text(paragraph, text)
|
|
1060
|
+
return paragraph
|
|
1061
|
+
|
|
1062
|
+
|
|
1055
1063
|
def add_horizontal_rule(paragraph):
|
|
1056
1064
|
"""Render a horizontal Markdown rule as a Word paragraph border."""
|
|
1057
1065
|
from docx.oxml import OxmlElement
|
|
@@ -1350,16 +1358,16 @@ def write_docx(path, title, content_markdown, product_name):
|
|
|
1350
1358
|
and re.sub(r"\W+", "", heading_text).casefold()
|
|
1351
1359
|
== re.sub(r"\W+", "", title).casefold()
|
|
1352
1360
|
):
|
|
1353
|
-
doc
|
|
1361
|
+
add_markdown_heading(doc, heading_text, min(len(heading.group(1)), 4))
|
|
1354
1362
|
keep_checklist_together = "checklist" in heading_text.casefold()
|
|
1355
1363
|
index += 1
|
|
1356
1364
|
elif standalone_bold_heading:
|
|
1357
1365
|
flush_paragraph()
|
|
1358
|
-
doc
|
|
1366
|
+
add_markdown_heading(doc, standalone_bold_heading.group(1).strip(), 3)
|
|
1359
1367
|
index += 1
|
|
1360
1368
|
elif inferred_heading:
|
|
1361
1369
|
flush_paragraph()
|
|
1362
|
-
doc
|
|
1370
|
+
add_markdown_heading(doc, stripped, inferred_heading)
|
|
1363
1371
|
keep_checklist_together = "checklist" in stripped.casefold()
|
|
1364
1372
|
index += 1
|
|
1365
1373
|
elif fact:
|
|
@@ -1428,11 +1436,85 @@ def write_markdown(path, title, content_markdown, product_name):
|
|
|
1428
1436
|
path.write_text("\n\n".join(part for part in parts if part), encoding="utf-8")
|
|
1429
1437
|
|
|
1430
1438
|
|
|
1439
|
+
def reconcile_public_copy_counts(content_markdown):
|
|
1440
|
+
"""Replace stale public-copy counts with deterministic local counts.
|
|
1441
|
+
|
|
1442
|
+
AI hosts sometimes leave ``NOT VERIFIED`` or an estimated count beside a
|
|
1443
|
+
marked public-copy body. The local runtime can resolve that mechanical
|
|
1444
|
+
value without transmitting the document. It changes only count lines tied
|
|
1445
|
+
to balanced PUBLIC COPY markers and a detectable numeric maximum.
|
|
1446
|
+
"""
|
|
1447
|
+
start_marker = "<!-- PUBLIC COPY START -->"
|
|
1448
|
+
end_marker = "<!-- PUBLIC COPY END -->"
|
|
1449
|
+
if content_markdown.count(start_marker) != content_markdown.count(end_marker):
|
|
1450
|
+
return content_markdown
|
|
1451
|
+
|
|
1452
|
+
blocks = list(
|
|
1453
|
+
re.finditer(
|
|
1454
|
+
re.escape(start_marker) + r"\n?(.*?)\n?" + re.escape(end_marker),
|
|
1455
|
+
content_markdown,
|
|
1456
|
+
re.DOTALL,
|
|
1457
|
+
)
|
|
1458
|
+
)
|
|
1459
|
+
if not blocks:
|
|
1460
|
+
return content_markdown
|
|
1461
|
+
|
|
1462
|
+
count_pattern = re.compile(
|
|
1463
|
+
r"(?im)^(?P<prefix>\s*(?:\*\*)?Deterministic count:(?:\*\*)?\s*)"
|
|
1464
|
+
r"(?P<actual>NOT VERIFIED|[\d,]+)"
|
|
1465
|
+
r"(?:\s*/\s*(?P<target>[\d,]+)\s*(?P<unit>words|characters))?\s*$"
|
|
1466
|
+
)
|
|
1467
|
+
limit_patterns = (
|
|
1468
|
+
re.compile(r"(?i)\bmaximum(?:\s+public[- ]copy\s+length)?\s+(?:is\s+)?([\d,]+)\s*(words|characters)\b"),
|
|
1469
|
+
re.compile(r"(?i)\bmax(?:imum)?\s*[:=]?\s*([\d,]+)\s*(words|characters)\b"),
|
|
1470
|
+
re.compile(r"(?i)\b([\d,]+)[ -](word|character)\s+maximum\b"),
|
|
1471
|
+
)
|
|
1472
|
+
|
|
1473
|
+
replacements = []
|
|
1474
|
+
count_matches = list(count_pattern.finditer(content_markdown))
|
|
1475
|
+
for block in blocks:
|
|
1476
|
+
following = [match for match in count_matches if match.start() >= block.end()]
|
|
1477
|
+
if not following:
|
|
1478
|
+
continue
|
|
1479
|
+
count_match = min(following, key=lambda match: match.start() - block.end())
|
|
1480
|
+
if count_match.start() - block.end() > 2000:
|
|
1481
|
+
continue
|
|
1482
|
+
|
|
1483
|
+
target_text = count_match.group("target")
|
|
1484
|
+
unit = (count_match.group("unit") or "").lower()
|
|
1485
|
+
if not target_text or not unit:
|
|
1486
|
+
limit_match = None
|
|
1487
|
+
for pattern in limit_patterns:
|
|
1488
|
+
limit_match = pattern.search(content_markdown)
|
|
1489
|
+
if limit_match:
|
|
1490
|
+
break
|
|
1491
|
+
if not limit_match:
|
|
1492
|
+
continue
|
|
1493
|
+
target_text = limit_match.group(1)
|
|
1494
|
+
unit = limit_match.group(2).lower()
|
|
1495
|
+
if unit == "word":
|
|
1496
|
+
unit = "words"
|
|
1497
|
+
elif unit == "character":
|
|
1498
|
+
unit = "characters"
|
|
1499
|
+
|
|
1500
|
+
target = int(target_text.replace(",", ""))
|
|
1501
|
+
body = block.group(1)
|
|
1502
|
+
actual = len(body) if unit == "characters" else len(re.findall(r"\S+", body))
|
|
1503
|
+
replacement = f"{count_match.group('prefix')}{actual} / {target} {unit}"
|
|
1504
|
+
replacements.append((count_match.start(), count_match.end(), replacement))
|
|
1505
|
+
|
|
1506
|
+
corrected = content_markdown
|
|
1507
|
+
for start, end, replacement in reversed(replacements):
|
|
1508
|
+
corrected = corrected[:start] + replacement + corrected[end:]
|
|
1509
|
+
return corrected
|
|
1510
|
+
|
|
1511
|
+
|
|
1431
1512
|
def save_document(arguments, product_name):
|
|
1432
1513
|
"""Save AI-produced final content to a local downloadable file."""
|
|
1433
1514
|
content_markdown = (arguments.get("content_markdown") or arguments.get("content") or "").strip()
|
|
1434
1515
|
if not content_markdown:
|
|
1435
1516
|
raise ValueError("content_markdown is required.")
|
|
1517
|
+
content_markdown = reconcile_public_copy_counts(content_markdown)
|
|
1436
1518
|
|
|
1437
1519
|
title = (arguments.get("title") or "").strip()
|
|
1438
1520
|
skill_id = (arguments.get("skill_id") or "").strip()
|