agentlas 1.0.21 → 1.0.22

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.22 — 2026-08-01
4
+
5
+ - **Task classes no longer come from a fixed keyword dictionary.** An explicit
6
+ user/project declaration remains authoritative; otherwise only the connected
7
+ model may classify the full request, and an unavailable or invalid judgment
8
+ stays unresolved.
9
+ - Preserve an explicit `declaredTaskClasses` value across the Desktop loadout
10
+ boundary so removing the dictionary fallback does not discard user-owned
11
+ structured intent.
12
+
3
13
  ## 1.0.21 — 2026-08-01
4
14
 
5
15
  - Align the independent Terminal sentence with the exact cross-surface
@@ -1469,41 +1469,6 @@ async function withdrawUpload(ref, options = {}) {
1469
1469
  return { receipt, authoritative: "server", publicActivation: false };
1470
1470
  }
1471
1471
 
1472
- const TASK_CLASS_KEYWORDS = Object.freeze({
1473
- research: ["research", "investigate", "literature review", "market research", "리서치", "연구", "자료 조사"],
1474
- writing: ["writing", "write article", "write copy", "copywriting", "blog post", "essay", "글쓰기", "글 작성", "카피 작성", "원고 작성"],
1475
- coding: ["coding", "code implementation", "implement code", "write code", "source code", "코딩", "코드 구현", "코드 작성", "프로그래밍"],
1476
- debugging: ["debug", "debugging", "bug fix", "fix bug", "troubleshoot", "error", "exception", "failure", "failed", "디버깅", "버그 수정", "오류", "오류 수정", "실패"],
1477
- design: ["design", "ui design", "ux design", "wireframe", "디자인", "와이어프레임", "화면 설계"],
1478
- "image-generation": ["image generation", "generate image", "create image", "text to image", "이미지 생성", "그림 생성"],
1479
- "video-production": ["video production", "create video", "video editing", "영상 제작", "비디오 제작", "영상 편집"],
1480
- presentation: ["presentation", "slide deck", "powerpoint", "ppt", "프레젠테이션", "발표 자료", "슬라이드", "피피티"],
1481
- document: ["document", "docx", "pdf document", "document editing", "문서", "문서 작성", "문서 편집"],
1482
- "data-analysis": ["data analysis", "analyze data", "analytics", "데이터 분석", "통계 분석"],
1483
- "browser-automation": ["browser automation", "automate browser", "playwright", "브라우저 자동화", "웹 자동화"],
1484
- "social-publishing": ["social publishing", "publish social", "post to instagram", "post to tiktok", "sns 게시", "소셜 게시", "인스타 업로드", "틱톡 업로드"],
1485
- marketing: ["marketing", "campaign", "seo", "마케팅", "캠페인"],
1486
- sales: ["sales", "lead generation", "sales outreach", "영업", "리드 발굴"],
1487
- "customer-support": ["customer support", "customer service", "support ticket", "고객 지원", "고객 문의", "cs 응대"],
1488
- ecommerce: ["ecommerce", "e commerce", "online store", "shopify", "이커머스", "온라인 쇼핑몰", "스마트스토어"],
1489
- "legal-review": ["legal review", "contract review", "legal analysis", "법률 검토", "계약 검토", "법무 검토"],
1490
- finance: ["finance", "financial analysis", "investment analysis", "재무", "금융", "투자 분석"],
1491
- "project-planning": ["project planning", "project plan", "roadmap", "프로젝트 계획", "로드맵", "일정 계획"],
1492
- "agent-building": ["agent building", "build agent", "create agent", "에이전트 빌드", "에이전트 만들", "에이전트 생성"],
1493
- "workflow-automation": ["workflow automation", "automate workflow", "automation workflow", "워크플로 자동화", "업무 자동화"],
1494
- "file-operations": ["file operations", "move files", "rename files", "organize files", "파일 작업", "파일 이동", "파일 이름 변경", "파일 정리"],
1495
- translation: ["translation", "translate", "localization", "번역", "현지화"],
1496
- });
1497
-
1498
- function normalizeClassificationText(value) {
1499
- return String(value || "")
1500
- .normalize("NFKC")
1501
- .toLowerCase()
1502
- .replace(/[^a-z0-9가-힣]+/gi, " ")
1503
- .replace(/\s+/g, " ")
1504
- .trim();
1505
- }
1506
-
1507
1472
  function normalizedTaxonomyAtom(value) {
1508
1473
  return typeof value === "string" ? value.normalize("NFKC").trim().toLowerCase() : "";
1509
1474
  }
@@ -1525,20 +1490,7 @@ function isCanonicalTaskId(value) {
1525
1490
  return typeof value === "string" && CANONICAL_TASK_ID_SET.has(value);
1526
1491
  }
1527
1492
 
1528
- function keywordOccurs(normalizedPrompt, rawKeyword) {
1529
- const keyword = normalizeClassificationText(rawKeyword);
1530
- if (!keyword) return false;
1531
- if (/[가-힣]/.test(keyword)) {
1532
- // Korean has no word boundary, so a raw includes() matched inside longer compounds:
1533
- // 번역 hit 번역기, 금융 hit compound finance words, 영업 hit 영업일 (business day).
1534
- // Require the keyword not be glued to another Hangul syllable on either side.
1535
- const escaped = keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1536
- return new RegExp(`(?<![가-힣])${escaped}(?![가-힣])`).test(normalizedPrompt);
1537
- }
1538
- return ` ${normalizedPrompt} `.includes(` ${keyword} `);
1539
- }
1540
-
1541
- function deriveCanonicalTaskClasses(prompt, options = {}) {
1493
+ function deriveCanonicalTaskClasses(_prompt, options = {}) {
1542
1494
  const declaredRaw = options.declaredTaskClasses ?? options.declaredTaskClass;
1543
1495
  if (declaredRaw != null && (Array.isArray(declaredRaw) ? declaredRaw.length : String(declaredRaw).trim())) {
1544
1496
  const declared = (Array.isArray(declaredRaw) ? declaredRaw : [declaredRaw]).map(String);
@@ -1551,39 +1503,23 @@ function deriveCanonicalTaskClasses(prompt, options = {}) {
1551
1503
  invalidDeclaredCount: invalidDeclared.length,
1552
1504
  };
1553
1505
  }
1554
- const normalizedPrompt = normalizeClassificationText(prompt);
1555
- const matches = [];
1556
- for (const slug of CANONICAL_TASK_SLUGS) {
1557
- if ((TASK_CLASS_KEYWORDS[slug] || []).some((keyword) => keywordOccurs(normalizedPrompt, keyword))) {
1558
- matches.push(`${CANONICAL_TASK_PREFIX}${slug}`);
1559
- }
1560
- }
1561
- return { taskIds: matches, source: "deterministic-keyword-map", matchedTaskClasses: matches, invalidDeclaredCount: 0 };
1506
+ return { taskIds: [], source: "unresolved", matchedTaskClasses: [], invalidDeclaredCount: 0 };
1562
1507
  }
1563
1508
 
1564
1509
  /**
1565
- * Meaning-aware task classification. The resident judge decides; TASK_CLASS_KEYWORDS is
1566
- * passed as reference hints only. This is what a keyword map cannot do: Korean compounds
1567
- * (번역 inside 번역기), particle inflection (고객 문의를), dialect, slang, and any other
1568
- * language all hinge on meaning, and no list enumerates them.
1569
- *
1570
- * An explicit declared task class still wins outright (it is data, not a guess), and with
1571
- * no connected model the deterministic keyword prefilter is the fallback so classification
1572
- * never stops working.
1510
+ * Meaning-aware task classification. An explicit declared class is accepted as
1511
+ * user/project data. Otherwise only the connected model may decide from the full
1512
+ * request. No regex, keyword list, glossary, or default class substitutes for a
1513
+ * missing or invalid model judgment.
1573
1514
  */
1574
1515
  async function resolveCanonicalTaskClasses(prompt, options = {}) {
1575
1516
  const declaredRaw = options.declaredTaskClasses ?? options.declaredTaskClass;
1576
1517
  if (declaredRaw != null && (Array.isArray(declaredRaw) ? declaredRaw.length : String(declaredRaw).trim())) {
1577
1518
  return deriveCanonicalTaskClasses(prompt, options);
1578
1519
  }
1579
- const prefilter = deriveCanonicalTaskClasses(prompt, options);
1580
1520
  const judgment = require("./agentlas-judgment.cjs");
1581
- if (!judgment.hasJudgmentRunner()) return prefilter;
1582
-
1583
- const hints = {};
1584
- for (const slug of CANONICAL_TASK_SLUGS) {
1585
- const words = TASK_CLASS_KEYWORDS[slug];
1586
- if (Array.isArray(words) && words.length) hints[slug] = words;
1521
+ if (!judgment.hasJudgmentRunner()) {
1522
+ return { taskIds: [], source: "model-unavailable", matchedTaskClasses: [], invalidDeclaredCount: 0 };
1587
1523
  }
1588
1524
  const verdict = await judgment.judgeLabels({
1589
1525
  kind: "experience-task-class",
@@ -1595,11 +1531,11 @@ async function resolveCanonicalTaskClasses(prompt, options = {}) {
1595
1531
  "Return a label only when that kind of work is genuinely part of the request. A word inside an " +
1596
1532
  "unrelated compound or a different sense of the word does not count. Return an empty list for " +
1597
1533
  "content with no identifiable task (hashes, ids, random strings).",
1598
- hints,
1599
- fallback: [],
1600
1534
  signal: options.signal,
1601
1535
  });
1602
- if (verdict.source !== "llm") return prefilter;
1536
+ if (verdict.source !== "llm") {
1537
+ return { taskIds: [], source: "model-unavailable", matchedTaskClasses: [], invalidDeclaredCount: 0 };
1538
+ }
1603
1539
  const taskIds = CANONICAL_TASK_IDS.filter((id) =>
1604
1540
  verdict.labels.some((slug) => id === `${CANONICAL_TASK_PREFIX}${slug}`));
1605
1541
  return {
@@ -137,6 +137,7 @@ function resolveRuntimeExperienceCli(agent, prompt, requested, cwd, overrides =
137
137
  cwd,
138
138
  prompt,
139
139
  requested: prepared.requested || requested || {},
140
+ declaredTaskClasses: requested && requested.declaredTaskClasses,
140
141
  agent,
141
142
  agentRoot: agent ? (overrides.agentRoot || agentFolder(agent)) : null,
142
143
  ...(overrides.platform ? { platform: overrides.platform } : {}),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentlas",
3
- "version": "1.0.21",
3
+ "version": "1.0.22",
4
4
  "description": "Agentlas agent terminal — chat with your installed AI agents and teams from the terminal, Claude Code style. Standalone: no desktop app required.",
5
5
  "bin": {
6
6
  "agentlas": "bin/agentlas.cjs"