open-agents-ai 0.72.1 → 0.73.0

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.
Files changed (2) hide show
  1. package/dist/index.js +256 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -15097,6 +15097,23 @@ These tools use OS cron (survives process death) and persist state to .oa/ for c
15097
15097
  Use cron_agent for recurring autonomous tasks, scheduler for simple repeating commands,
15098
15098
  reminder for deferred attention, and agenda for strategic focus tracking.
15099
15099
 
15100
+ ## Priority Ingress \u2014 Task Classification & Delegation
15101
+
15102
+ When multiple tasks arrive (Telegram, reminders, updates), classify and route them:
15103
+ - priority_classify: Determine a task's priority (critical/high/moderate/normal/low/salient)
15104
+ priority_classify(message='...', source='external', origin='telegram')
15105
+ Returns: priority, weight, delegable flag, handling policy
15106
+ - priority_delegate: Send normal/low/salient tasks to a sub-agent
15107
+ priority_delegate(task_prompt='...', priority='normal')
15108
+
15109
+ Priority handling policies:
15110
+ CRITICAL (100): Interrupt immediately. Handle now.
15111
+ HIGH (80): Interrupt at turn boundary. Handle next.
15112
+ MODERATE (60): Queue, run after current task.
15113
+ NORMAL (40): Can delegate to sub-agent.
15114
+ LOW (20): Should delegate to sub-agent.
15115
+ SALIENT (5): Note for later, delegate if possible.
15116
+
15100
15117
  ## Context Efficiency
15101
15118
 
15102
15119
  - Use grep_search to find specific code instead of reading many files
@@ -33655,6 +33672,216 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
33655
33672
  }
33656
33673
  });
33657
33674
 
33675
+ // packages/cli/dist/tui/priority-ingress.js
33676
+ function classifyPriority(prompt, source, origin) {
33677
+ for (const rule of CLASSIFICATION_RULES) {
33678
+ if (rule.sourceType !== "any" && rule.sourceType !== source)
33679
+ continue;
33680
+ if (rule.pattern.test(prompt)) {
33681
+ return { priority: rule.priority, confidence: rule.confidence };
33682
+ }
33683
+ }
33684
+ if (origin === "attention" || origin === "reminder") {
33685
+ return { priority: "moderate", confidence: 0.6 };
33686
+ }
33687
+ if (source === "external" && origin === "telegram") {
33688
+ return { priority: "normal", confidence: 0.65 };
33689
+ }
33690
+ if (origin === "dmn") {
33691
+ return { priority: "low", confidence: 0.7 };
33692
+ }
33693
+ if (origin === "update") {
33694
+ return { priority: "moderate", confidence: 0.85 };
33695
+ }
33696
+ return { priority: "normal", confidence: 0.5 };
33697
+ }
33698
+ var PRIORITY_WEIGHT, PRIORITY_POLICIES, CLASSIFICATION_RULES, PriorityIngressEngine;
33699
+ var init_priority_ingress = __esm({
33700
+ "packages/cli/dist/tui/priority-ingress.js"() {
33701
+ "use strict";
33702
+ PRIORITY_WEIGHT = {
33703
+ critical: 100,
33704
+ high: 80,
33705
+ moderate: 60,
33706
+ normal: 40,
33707
+ low: 20,
33708
+ salient: 5
33709
+ };
33710
+ PRIORITY_POLICIES = {
33711
+ critical: { canInterrupt: true, canDelegate: false, maxWaitMs: 0, notifyAdmin: true },
33712
+ high: { canInterrupt: true, canDelegate: false, maxWaitMs: 0, notifyAdmin: true },
33713
+ moderate: { canInterrupt: false, canDelegate: false, maxWaitMs: 3e4, notifyAdmin: false },
33714
+ normal: { canInterrupt: false, canDelegate: true, maxWaitMs: 6e4, notifyAdmin: false },
33715
+ low: { canInterrupt: false, canDelegate: true, maxWaitMs: 3e5, notifyAdmin: false },
33716
+ salient: { canInterrupt: false, canDelegate: true, maxWaitMs: 9e5, notifyAdmin: false }
33717
+ };
33718
+ CLASSIFICATION_RULES = [
33719
+ // CRITICAL — show-stoppers
33720
+ { pattern: /\b(security breach|data loss|compromised|urgent.*fix|production down|critical.*failure)\b/i, sourceType: "any", priority: "critical", confidence: 0.95 },
33721
+ { pattern: /\bCRITICAL\b/, sourceType: "any", priority: "critical", confidence: 0.9 },
33722
+ // HIGH — important interrupts
33723
+ { pattern: /\b(failing ci|build broken|tests? failing|deployment failed|regression)\b/i, sourceType: "any", priority: "high", confidence: 0.85 },
33724
+ { pattern: /\b(URGENT|ASAP|immediately|right now)\b/i, sourceType: "external", priority: "high", confidence: 0.8 },
33725
+ // MODERATE — significant but non-interrupt
33726
+ { pattern: /\b(update available|new version|upgrade)\b/i, sourceType: "any", priority: "moderate", confidence: 0.85 },
33727
+ { pattern: /\b(admin|owner)\b/i, sourceType: "external", priority: "moderate", confidence: 0.7 },
33728
+ // LOW — background tasks
33729
+ { pattern: /\b(routine|check|status|health)\b/i, sourceType: "internal", priority: "low", confidence: 0.75 },
33730
+ { pattern: /\b(FYI|notice|info|heads up)\b/i, sourceType: "any", priority: "salient", confidence: 0.8 }
33731
+ ];
33732
+ PriorityIngressEngine = class {
33733
+ queue = [];
33734
+ completedTasks = [];
33735
+ taskCounter = 0;
33736
+ /** Callback: notify admin about high-priority tasks */
33737
+ adminNotify;
33738
+ /** Callback: request attention switch from current task */
33739
+ requestInterrupt;
33740
+ /** Callback: delegate task to sub-agent */
33741
+ delegateToSubAgent;
33742
+ constructor() {
33743
+ }
33744
+ /** Wire callbacks after construction (Telegram/agent may not be ready at construction time) */
33745
+ setAdminNotify(cb) {
33746
+ this.adminNotify = cb;
33747
+ }
33748
+ setInterruptHandler(cb) {
33749
+ this.requestInterrupt = cb;
33750
+ }
33751
+ setDelegationHandler(cb) {
33752
+ this.delegateToSubAgent = cb;
33753
+ }
33754
+ /**
33755
+ * Ingest a new task from any source.
33756
+ * Classifies priority, applies handling policy, and routes accordingly.
33757
+ */
33758
+ ingest(prompt, source, origin, metadata, overridePriority) {
33759
+ const classification = overridePriority ? { priority: overridePriority, confidence: 1 } : classifyPriority(prompt, source, origin);
33760
+ const policy = PRIORITY_POLICIES[classification.priority];
33761
+ const task = {
33762
+ id: `task-${++this.taskCounter}-${Date.now()}`,
33763
+ source,
33764
+ origin,
33765
+ priority: classification.priority,
33766
+ prompt,
33767
+ metadata,
33768
+ ingressAt: Date.now(),
33769
+ delegable: policy.canDelegate,
33770
+ confidence: classification.confidence,
33771
+ status: "pending"
33772
+ };
33773
+ if (policy.notifyAdmin && this.adminNotify) {
33774
+ const priorityLabel = classification.priority.toUpperCase();
33775
+ const preview = prompt.length > 120 ? prompt.slice(0, 120) + "..." : prompt;
33776
+ this.adminNotify(`[${priorityLabel}] ${origin}: ${preview}`);
33777
+ }
33778
+ if (policy.canInterrupt && this.requestInterrupt) {
33779
+ this.requestInterrupt(task);
33780
+ task.status = "active";
33781
+ } else if (policy.canDelegate && this.delegateToSubAgent) {
33782
+ task.status = "delegated";
33783
+ this.delegateToSubAgent(task).then((summary) => {
33784
+ task.status = "completed";
33785
+ task.completionSummary = summary;
33786
+ this.completedTasks.push(task);
33787
+ }).catch(() => {
33788
+ task.status = "pending";
33789
+ task.priority = "moderate";
33790
+ task.delegable = false;
33791
+ this.queue.push(task);
33792
+ this.sortQueue();
33793
+ });
33794
+ } else {
33795
+ this.queue.push(task);
33796
+ this.sortQueue();
33797
+ }
33798
+ return task;
33799
+ }
33800
+ /**
33801
+ * Get the next task from the priority queue.
33802
+ * Returns null if queue is empty.
33803
+ * Implements weighted scoring: priority_weight + recency_bonus
33804
+ * (REF: Generative Agents scoring — importance + recency)
33805
+ */
33806
+ dequeue() {
33807
+ if (this.queue.length === 0)
33808
+ return null;
33809
+ const task = this.queue.shift();
33810
+ task.status = "active";
33811
+ return task;
33812
+ }
33813
+ /** Mark a task as completed */
33814
+ complete(taskId, summary) {
33815
+ const idx = this.queue.findIndex((t) => t.id === taskId);
33816
+ if (idx >= 0) {
33817
+ const task = this.queue.splice(idx, 1)[0];
33818
+ task.status = "completed";
33819
+ task.completionSummary = summary;
33820
+ this.completedTasks.push(task);
33821
+ }
33822
+ }
33823
+ /** Mark active task as completed (when we don't track by ID) */
33824
+ completeActive(summary) {
33825
+ this.completedTasks.push({
33826
+ id: `completed-${Date.now()}`,
33827
+ source: "internal",
33828
+ origin: "main",
33829
+ priority: "normal",
33830
+ prompt: "",
33831
+ ingressAt: Date.now(),
33832
+ delegable: false,
33833
+ confidence: 1,
33834
+ status: "completed",
33835
+ completionSummary: summary
33836
+ });
33837
+ }
33838
+ /** Check if there are pending tasks that can interrupt */
33839
+ hasInterruptibleTask() {
33840
+ return this.queue.some((t) => {
33841
+ const policy = PRIORITY_POLICIES[t.priority];
33842
+ return policy.canInterrupt;
33843
+ });
33844
+ }
33845
+ /** Get queue length */
33846
+ get pending() {
33847
+ return this.queue.length;
33848
+ }
33849
+ /** Get stats */
33850
+ getStats() {
33851
+ const byPriority = {
33852
+ critical: 0,
33853
+ high: 0,
33854
+ moderate: 0,
33855
+ normal: 0,
33856
+ low: 0,
33857
+ salient: 0
33858
+ };
33859
+ const bySources = {};
33860
+ for (const t of [...this.queue, ...this.completedTasks]) {
33861
+ byPriority[t.priority]++;
33862
+ bySources[t.origin] = (bySources[t.origin] ?? 0) + 1;
33863
+ }
33864
+ return {
33865
+ pending: this.queue.length,
33866
+ completed: this.completedTasks.length,
33867
+ byPriority,
33868
+ bySources
33869
+ };
33870
+ }
33871
+ /** Sort queue by priority weight (descending), then by recency (FIFO within priority) */
33872
+ sortQueue() {
33873
+ this.queue.sort((a, b) => {
33874
+ const wa = PRIORITY_WEIGHT[a.priority];
33875
+ const wb = PRIORITY_WEIGHT[b.priority];
33876
+ if (wa !== wb)
33877
+ return wb - wa;
33878
+ return a.ingressAt - b.ingressAt;
33879
+ });
33880
+ }
33881
+ };
33882
+ }
33883
+ });
33884
+
33658
33885
  // packages/cli/dist/tui/bless-engine.js
33659
33886
  function renderBlessStart() {
33660
33887
  process.stdout.write(`
@@ -33683,6 +33910,7 @@ var init_bless_engine = __esm({
33683
33910
  "use strict";
33684
33911
  init_render();
33685
33912
  init_dist2();
33913
+ init_priority_ingress();
33686
33914
  BlessEngine = class {
33687
33915
  config;
33688
33916
  repoRoot;
@@ -33696,6 +33924,8 @@ var init_bless_engine = __esm({
33696
33924
  };
33697
33925
  /** Pending tasks from external sources (telegram, reminders, etc.) */
33698
33926
  pendingQueue = [];
33927
+ /** Priority-aware ingress engine */
33928
+ priorityEngine = new PriorityIngressEngine();
33699
33929
  constructor(config, repoRoot) {
33700
33930
  this.config = config;
33701
33931
  this.repoRoot = repoRoot;
@@ -33739,36 +33969,44 @@ var init_bless_engine = __esm({
33739
33969
  /** Enqueue a task from an external source (e.g., Telegram) */
33740
33970
  enqueueTask(source, prompt, chatId) {
33741
33971
  this.pendingQueue.push({ source, prompt, chatId });
33972
+ const taskSource = source === "telegram" || source === "webhook" ? "external" : "internal";
33973
+ this.priorityEngine.ingest(prompt, taskSource, source, chatId != null ? { chatId } : void 0);
33742
33974
  }
33743
- /** Check for pending tasks from any source. Returns next task or null. */
33975
+ /** Check for pending tasks from any source. Returns next task or null.
33976
+ * Uses priority-weighted ordering (REF: Nalar arXiv:2601.05109 two-level control).
33977
+ * Priority queue is checked first, then reminders/attention items are ingested. */
33744
33978
  async getNextTask() {
33745
- if (this.pendingQueue.length > 0) {
33746
- return this.pendingQueue.shift();
33747
- }
33748
33979
  try {
33749
33980
  const dueReminders = await getDueReminders(this.repoRoot);
33750
- const critical = dueReminders.filter((r) => r.priority === "critical" && r.status === "pending");
33751
- if (critical.length > 0) {
33752
- const r = critical[0];
33753
- return {
33754
- source: "reminder",
33755
- prompt: `URGENT REMINDER: ${r.message}${r.tags?.length ? ` [tags: ${r.tags.join(", ")}]` : ""}. Check the agenda for full context and take appropriate action.`
33756
- };
33981
+ for (const r of dueReminders.filter((r2) => r2.status === "pending")) {
33982
+ const priority = r.priority === "critical" ? "critical" : r.priority === "high" ? "high" : "moderate";
33983
+ const prompt = `${priority === "critical" ? "URGENT " : ""}REMINDER: ${r.message}${r.tags?.length ? ` [tags: ${r.tags.join(", ")}]` : ""}. Check the agenda for full context and take appropriate action.`;
33984
+ this.priorityEngine.ingest(prompt, "internal", "reminder", { reminderId: r.id }, priority);
33757
33985
  }
33758
33986
  } catch {
33759
33987
  }
33760
33988
  try {
33761
33989
  const items = await getActiveAttentionItems(this.repoRoot);
33762
- const critical = items.filter((a) => a.priority === "critical");
33763
- if (critical.length > 0) {
33764
- const a = critical[0];
33765
- return {
33766
- source: "attention",
33767
- prompt: `CRITICAL ATTENTION ITEM: [${a.category}] ${a.title}${a.description ? ": " + a.description : ""}. Investigate and take action.`
33768
- };
33990
+ for (const a of items.filter((a2) => a2.priority === "critical")) {
33991
+ const prompt = `CRITICAL ATTENTION ITEM: [${a.category}] ${a.title}${a.description ? ": " + a.description : ""}. Investigate and take action.`;
33992
+ this.priorityEngine.ingest(prompt, "internal", "attention", void 0, "critical");
33769
33993
  }
33770
33994
  } catch {
33771
33995
  }
33996
+ if (this.pendingQueue.length > 0) {
33997
+ const item = this.pendingQueue.shift();
33998
+ const classification = classifyPriority(item.prompt, "external", item.source);
33999
+ return { ...item, priority: classification.priority };
34000
+ }
34001
+ const task = this.priorityEngine.dequeue();
34002
+ if (task) {
34003
+ return {
34004
+ source: task.origin,
34005
+ prompt: task.prompt,
34006
+ chatId: task.metadata?.chatId,
34007
+ priority: task.priority
34008
+ };
34009
+ }
33772
34010
  return null;
33773
34011
  }
33774
34012
  /** Record that a task was processed */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.72.1",
3
+ "version": "0.73.0",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",