@dotsetlabs/dotclaw 2.0.0 → 2.2.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 (138) hide show
  1. package/.env.example +12 -0
  2. package/README.md +7 -6
  3. package/config-examples/runtime.json +56 -121
  4. package/config-examples/tool-budgets.json +1 -1
  5. package/config-examples/tool-policy.json +3 -16
  6. package/container/Dockerfile +5 -1
  7. package/container/agent-runner/package.json +1 -1
  8. package/container/agent-runner/src/agent-config.ts +71 -55
  9. package/container/agent-runner/src/container-protocol.ts +9 -10
  10. package/container/agent-runner/src/daemon.ts +18 -5
  11. package/container/agent-runner/src/index.ts +567 -637
  12. package/container/agent-runner/src/ipc.ts +67 -54
  13. package/container/agent-runner/src/mcp-registry.ts +11 -0
  14. package/container/agent-runner/src/memory.ts +139 -1
  15. package/container/agent-runner/src/process-registry.ts +257 -0
  16. package/container/agent-runner/src/system-prompt.ts +311 -0
  17. package/container/agent-runner/src/tools.ts +379 -284
  18. package/container/agent-runner/src/tts.ts +42 -0
  19. package/dist/agent-context.d.ts +1 -0
  20. package/dist/agent-context.d.ts.map +1 -1
  21. package/dist/agent-context.js +6 -3
  22. package/dist/agent-context.js.map +1 -1
  23. package/dist/agent-execution.d.ts +5 -10
  24. package/dist/agent-execution.d.ts.map +1 -1
  25. package/dist/agent-execution.js +25 -26
  26. package/dist/agent-execution.js.map +1 -1
  27. package/dist/config.d.ts +1 -2
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js +1 -2
  30. package/dist/config.js.map +1 -1
  31. package/dist/container-protocol.d.ts +11 -10
  32. package/dist/container-protocol.d.ts.map +1 -1
  33. package/dist/container-runner.d.ts.map +1 -1
  34. package/dist/container-runner.js +44 -8
  35. package/dist/container-runner.js.map +1 -1
  36. package/dist/dashboard.d.ts +0 -6
  37. package/dist/dashboard.d.ts.map +1 -1
  38. package/dist/dashboard.js +1 -55
  39. package/dist/dashboard.js.map +1 -1
  40. package/dist/db.d.ts +1 -46
  41. package/dist/db.d.ts.map +1 -1
  42. package/dist/db.js +0 -192
  43. package/dist/db.js.map +1 -1
  44. package/dist/error-messages.d.ts.map +1 -1
  45. package/dist/error-messages.js +5 -1
  46. package/dist/error-messages.js.map +1 -1
  47. package/dist/index.js +58 -57
  48. package/dist/index.js.map +1 -1
  49. package/dist/ipc-dispatcher.d.ts.map +1 -1
  50. package/dist/ipc-dispatcher.js +330 -183
  51. package/dist/ipc-dispatcher.js.map +1 -1
  52. package/dist/maintenance.d.ts.map +1 -1
  53. package/dist/maintenance.js +3 -13
  54. package/dist/maintenance.js.map +1 -1
  55. package/dist/memory-recall.d.ts +1 -0
  56. package/dist/memory-recall.d.ts.map +1 -1
  57. package/dist/memory-recall.js +3 -0
  58. package/dist/memory-recall.js.map +1 -1
  59. package/dist/memory-store.d.ts.map +1 -1
  60. package/dist/memory-store.js +5 -3
  61. package/dist/memory-store.js.map +1 -1
  62. package/dist/message-pipeline.d.ts +1 -1
  63. package/dist/message-pipeline.d.ts.map +1 -1
  64. package/dist/message-pipeline.js +171 -374
  65. package/dist/message-pipeline.js.map +1 -1
  66. package/dist/metrics.d.ts +0 -3
  67. package/dist/metrics.d.ts.map +1 -1
  68. package/dist/metrics.js +2 -33
  69. package/dist/metrics.js.map +1 -1
  70. package/dist/model-registry.d.ts +15 -0
  71. package/dist/model-registry.d.ts.map +1 -1
  72. package/dist/model-registry.js +56 -12
  73. package/dist/model-registry.js.map +1 -1
  74. package/dist/providers/discord/discord-provider.d.ts.map +1 -1
  75. package/dist/providers/discord/discord-provider.js +6 -3
  76. package/dist/providers/discord/discord-provider.js.map +1 -1
  77. package/dist/providers/telegram/telegram-provider.d.ts +1 -0
  78. package/dist/providers/telegram/telegram-provider.d.ts.map +1 -1
  79. package/dist/providers/telegram/telegram-provider.js +14 -0
  80. package/dist/providers/telegram/telegram-provider.js.map +1 -1
  81. package/dist/request-router.d.ts +8 -31
  82. package/dist/request-router.d.ts.map +1 -1
  83. package/dist/request-router.js +24 -128
  84. package/dist/request-router.js.map +1 -1
  85. package/dist/runtime-config.d.ts +29 -101
  86. package/dist/runtime-config.d.ts.map +1 -1
  87. package/dist/runtime-config.js +96 -170
  88. package/dist/runtime-config.js.map +1 -1
  89. package/dist/streaming.d.ts +58 -0
  90. package/dist/streaming.d.ts.map +1 -0
  91. package/dist/streaming.js +196 -0
  92. package/dist/streaming.js.map +1 -0
  93. package/dist/task-scheduler.d.ts.map +1 -1
  94. package/dist/task-scheduler.js +10 -50
  95. package/dist/task-scheduler.js.map +1 -1
  96. package/dist/tool-budgets.js +1 -1
  97. package/dist/tool-budgets.js.map +1 -1
  98. package/dist/tool-policy.js +13 -13
  99. package/dist/tool-policy.js.map +1 -1
  100. package/dist/types.d.ts +0 -41
  101. package/dist/types.d.ts.map +1 -1
  102. package/dist/webhook.d.ts +14 -0
  103. package/dist/webhook.d.ts.map +1 -0
  104. package/dist/webhook.js +169 -0
  105. package/dist/webhook.js.map +1 -0
  106. package/package.json +3 -3
  107. package/scripts/configure.js +81 -0
  108. package/scripts/install.sh +1 -1
  109. package/config-examples/plugin-http.json +0 -18
  110. package/container/skills/agent-browser.md +0 -159
  111. package/dist/background-job-classifier.d.ts +0 -20
  112. package/dist/background-job-classifier.d.ts.map +0 -1
  113. package/dist/background-job-classifier.js +0 -145
  114. package/dist/background-job-classifier.js.map +0 -1
  115. package/dist/background-jobs.d.ts +0 -56
  116. package/dist/background-jobs.d.ts.map +0 -1
  117. package/dist/background-jobs.js +0 -559
  118. package/dist/background-jobs.js.map +0 -1
  119. package/dist/orchestration.d.ts +0 -39
  120. package/dist/orchestration.d.ts.map +0 -1
  121. package/dist/orchestration.js +0 -136
  122. package/dist/orchestration.js.map +0 -1
  123. package/dist/planner-probe.d.ts +0 -14
  124. package/dist/planner-probe.d.ts.map +0 -1
  125. package/dist/planner-probe.js +0 -97
  126. package/dist/planner-probe.js.map +0 -1
  127. package/dist/tool-intent-probe.d.ts +0 -11
  128. package/dist/tool-intent-probe.d.ts.map +0 -1
  129. package/dist/tool-intent-probe.js +0 -63
  130. package/dist/tool-intent-probe.js.map +0 -1
  131. package/dist/workflow-engine.d.ts +0 -51
  132. package/dist/workflow-engine.d.ts.map +0 -1
  133. package/dist/workflow-engine.js +0 -281
  134. package/dist/workflow-engine.js.map +0 -1
  135. package/dist/workflow-store.d.ts +0 -39
  136. package/dist/workflow-store.d.ts.map +0 -1
  137. package/dist/workflow-store.js +0 -173
  138. package/dist/workflow-store.js.map +0 -1
package/.env.example CHANGED
@@ -27,6 +27,12 @@ TZ=America/New_York
27
27
  # GitHub Personal Access Token (enables gh CLI in containers)
28
28
  # GH_TOKEN=ghp_your_token_here
29
29
 
30
+ # OpenAI API key (enables OpenAI TTS provider; falls back to OPENROUTER_API_KEY)
31
+ # OPENAI_API_KEY=sk-replace-with-openai-key
32
+
33
+ # Override vision model for the AnalyzeImage tool (defaults to openai/gpt-4o)
34
+ # DOTCLAW_VISION_MODEL=openai/gpt-4o
35
+
30
36
  # --- Optional: System (set in shell before starting) ---
31
37
  # Override DotClaw home directory (defaults to ~/.dotclaw)
32
38
  # DOTCLAW_HOME=~/.dotclaw
@@ -39,12 +45,18 @@ TZ=America/New_York
39
45
  # Required for non-interactive bootstrap
40
46
  # DOTCLAW_BOOTSTRAP_CHAT_ID=123456789
41
47
 
48
+ # Explicit provider selection (telegram or discord)
49
+ # DOTCLAW_BOOTSTRAP_PROVIDER=telegram
50
+
42
51
  # Optional bootstrap defaults
43
52
  # DOTCLAW_BOOTSTRAP_GROUP_NAME=main
44
53
  # DOTCLAW_BOOTSTRAP_GROUP_FOLDER=main
45
54
  # DOTCLAW_BOOTSTRAP_BUILD=true
46
55
  # DOTCLAW_BOOTSTRAP_SELF_CHECK=true
47
56
 
57
+ # Required for non-interactive configure
58
+ # DOTCLAW_CONFIGURE_CHAT_ID=123456789
59
+
48
60
  # --- Optional: autotune (advanced) ---
49
61
  # Autotune uses dotenv, so these can live in .env if you run `npm run autotune`.
50
62
  # AUTOTUNE_TRACE_DIR=~/.dotclaw/traces
package/README.md CHANGED
@@ -11,12 +11,10 @@ Personal OpenRouter-based assistant for Telegram and Discord. Each request runs
11
11
  - Voice transcription and text-to-speech
12
12
  - Browser automation (Chromium in-container)
13
13
  - MCP server integration (stdio transport)
14
- - Lifecycle hooks (message, agent, job, task, memory events)
15
- - Multi-agent orchestration (parallel fan-out with aggregation)
16
- - Declarative YAML/JSON workflows (multi-step pipelines)
14
+ - Lifecycle hooks (message, agent, task, memory events)
15
+ - Real-time streaming responses with edit-in-place delivery
17
16
  - Long-term memory with embeddings and semantic search
18
17
  - Scheduled tasks (cron and one-off)
19
- - Background jobs for long-running work
20
18
  - Tool policies and daily budgets
21
19
  - Plugin tools and Autotune optimization
22
20
  - Prometheus-compatible metrics and status dashboard
@@ -122,10 +120,13 @@ Or see:
122
120
 
123
121
  ```bash
124
122
  npm run dev # Run with hot reload
125
- npm run build # Compile TypeScript
123
+ npm run dev:up # Full dev cycle: rebuild container + kill stale daemons + start dev
124
+ npm run dev:down # Remove all running dotclaw agent containers
125
+ npm run build # Compile TypeScript (host)
126
+ npm run build:all # Build both host and container
126
127
  npm run lint # Run ESLint
127
128
  npm test # Run tests
128
- ./container/build.sh # Rebuild agent container
129
+ dotclaw build # Rebuild agent container (or: ./container/build.sh)
129
130
  ```
130
131
 
131
132
  ## License
@@ -15,118 +15,39 @@
15
15
  "port": 3002
16
16
  },
17
17
  "memory": {
18
+ "recall": {
19
+ "minScore": 0.35
20
+ },
18
21
  "embeddings": {
19
22
  "enabled": true
20
23
  }
21
24
  },
22
- "backgroundJobs": {
23
- "enabled": true,
24
- "maxConcurrent": 2,
25
- "maxRuntimeMs": 2400000,
26
- "maxToolSteps": 256,
27
- "toolDeny": ["mcp__dotclaw__spawn_job"],
28
- "progress": {
29
- "enabled": false,
30
- "startDelayMs": 30000,
31
- "intervalMs": 120000,
32
- "maxUpdates": 3
33
- },
34
- "autoSpawn": {
35
- "enabled": true,
36
- "foregroundTimeoutMs": 90000,
37
- "onTimeout": true,
38
- "onToolLimit": true,
39
- "classifier": {
40
- "enabled": true,
41
- "model": "deepseek/deepseek-v3.2",
42
- "timeoutMs": 3000,
43
- "maxOutputTokens": 32,
44
- "temperature": 0,
45
- "confidenceThreshold": 0.6,
46
- "adaptive": {
47
- "enabled": true,
48
- "minThreshold": 0.55,
49
- "maxThreshold": 0.65,
50
- "queueDepthLow": 0,
51
- "queueDepthHigh": 4
52
- }
53
- }
54
- }
55
- },
56
25
  "routing": {
26
+ "model": "moonshotai/kimi-k2.5",
27
+ "fallbacks": ["anthropic/claude-sonnet-4-5", "openai/gpt-4.1"],
28
+ "allowedModels": [],
29
+ "maxOutputTokens": 0,
30
+ "maxToolSteps": 200,
31
+ "temperature": 0.6,
32
+ "recallMaxResults": 8,
33
+ "recallMaxTokens": 1500
34
+ },
35
+ "webhook": {
36
+ "enabled": false,
37
+ "port": 3003,
38
+ "token": ""
39
+ },
40
+ "streaming": {
57
41
  "enabled": true,
58
- "maxFastChars": 200,
59
- "maxStandardChars": 1200,
60
- "backgroundMinChars": 2000,
61
- "fastKeywords": ["hi", "hello", "hey", "who are you", "what can you do", "help", "thanks", "thank you"],
62
- "deepKeywords": ["research", "analysis", "analyze", "report", "dashboard", "vibe", "refactor", "architecture", "design", "spec", "strategy", "migration", "benchmark", "investigate", "evaluate", "summarize", "long-running"],
63
- "backgroundKeywords": ["background", "long-running", "research", "deep dive", "multi-step", "multi step", "dashboard", "refactor", "benchmark", "report", "analysis", "survey", "crawl", "scrape", "codebase"],
64
- "classifierFallback": {
65
- "enabled": true,
66
- "minChars": 600
67
- },
68
- "plannerProbe": {
69
- "enabled": true,
70
- "model": "deepseek/deepseek-v3.2",
71
- "timeoutMs": 3000,
72
- "maxOutputTokens": 120,
73
- "temperature": 0,
74
- "minChars": 700,
75
- "minSteps": 4,
76
- "minTools": 3
77
- },
78
- "profiles": {
79
- "fast": {
80
- "model": "deepseek/deepseek-v3.2",
81
- "maxOutputTokens": 4096,
82
- "maxToolSteps": 12,
83
- "recallMaxResults": 0,
84
- "recallMaxTokens": 0,
85
- "enablePlanner": false,
86
- "enableValidation": false,
87
- "responseValidationMaxRetries": 0,
88
- "enableMemoryRecall": false,
89
- "enableMemoryExtraction": false,
90
- "progress": { "enabled": false }
91
- },
92
- "standard": {
93
- "model": "moonshotai/kimi-k2.5",
94
- "maxOutputTokens": 4096,
95
- "maxToolSteps": 48,
96
- "recallMaxResults": 6,
97
- "recallMaxTokens": 1500,
98
- "enablePlanner": true,
99
- "enableValidation": true,
100
- "responseValidationMaxRetries": 1,
101
- "enableMemoryRecall": true,
102
- "enableMemoryExtraction": true
103
- },
104
- "deep": {
105
- "model": "moonshotai/kimi-k2.5",
106
- "maxOutputTokens": 4096,
107
- "maxToolSteps": 128,
108
- "recallMaxResults": 12,
109
- "recallMaxTokens": 2500,
110
- "enablePlanner": true,
111
- "enableValidation": true,
112
- "responseValidationMaxRetries": 2,
113
- "enableMemoryRecall": true,
114
- "enableMemoryExtraction": true
115
- },
116
- "background": {
117
- "model": "moonshotai/kimi-k2.5",
118
- "maxOutputTokens": 4096,
119
- "maxToolSteps": 256,
120
- "recallMaxResults": 16,
121
- "recallMaxTokens": 4000,
122
- "enablePlanner": true,
123
- "enableValidation": true,
124
- "responseValidationMaxRetries": 2,
125
- "enableMemoryRecall": true,
126
- "enableMemoryExtraction": true,
127
- "progress": { "enabled": true, "initialMs": 15000, "intervalMs": 60000, "maxUpdates": 3 }
128
- }
129
- }
42
+ "chunkFlushIntervalMs": 200,
43
+ "editIntervalMs": 400,
44
+ "maxEditLength": 3800
45
+ },
46
+ "telegram": {
47
+ "enabled": true
48
+ },
49
+ "discord": {
50
+ "enabled": false
130
51
  },
131
52
  "toolBudgets": {
132
53
  "enabled": false
@@ -134,26 +55,40 @@
134
55
  },
135
56
  "agent": {
136
57
  "assistantName": "Rain",
58
+ "reasoning": { "effort": "medium" },
59
+ "context": {
60
+ "maxHistoryTurns": 40,
61
+ "contextPruning": {
62
+ "softTrimMaxChars": 4000,
63
+ "softTrimHeadChars": 1500,
64
+ "softTrimTailChars": 1500,
65
+ "keepLastAssistant": 3
66
+ }
67
+ },
137
68
  "promptPacks": {
138
69
  "enabled": true
139
70
  },
140
- "planner": {
141
- "enabled": true,
142
- "mode": "auto"
143
- },
144
- "responseValidation": {
145
- "enabled": true,
146
- "minPromptTokens": 400,
147
- "minResponseTokens": 160
148
- },
149
71
  "tools": {
150
- "progress": {
151
- "enabled": true,
152
- "minIntervalMs": 30000,
153
- "notifyTools": [],
154
- "notifyOnStart": false,
155
- "notifyOnError": false
72
+ "enableBash": true,
73
+ "enableWebSearch": true,
74
+ "enableWebFetch": true,
75
+ "bash": {
76
+ "timeoutMs": 600000
77
+ },
78
+ "process": {
79
+ "maxSessions": 16,
80
+ "maxOutputBytes": 1048576,
81
+ "defaultTimeoutMs": 1800000
156
82
  }
83
+ },
84
+ "tts": {
85
+ "provider": "edge-tts",
86
+ "openaiModel": "tts-1",
87
+ "openaiVoice": "alloy"
88
+ },
89
+ "mcp": {
90
+ "enabled": true,
91
+ "servers": []
157
92
  }
158
93
  }
159
94
  }
@@ -6,7 +6,7 @@
6
6
  "Bash": 2000,
7
7
  "Python": 1500,
8
8
  "GitClone": 400,
9
- "NpmInstall": 300
9
+ "PackageInstall": 300
10
10
  }
11
11
  },
12
12
  "groups": {
@@ -7,11 +7,12 @@
7
7
  "Glob",
8
8
  "Grep",
9
9
  "GitClone",
10
- "NpmInstall",
10
+ "PackageInstall",
11
11
  "WebSearch",
12
12
  "WebFetch",
13
13
  "Bash",
14
14
  "Python",
15
+ "Browser",
15
16
  "mcp__dotclaw__send_message",
16
17
  "mcp__dotclaw__send_file",
17
18
  "mcp__dotclaw__send_photo",
@@ -24,6 +25,7 @@
24
25
  "mcp__dotclaw__edit_message",
25
26
  "mcp__dotclaw__delete_message",
26
27
  "mcp__dotclaw__download_url",
28
+ "mcp__dotclaw__text_to_speech",
27
29
  "mcp__dotclaw__schedule_task",
28
30
  "mcp__dotclaw__run_task",
29
31
  "mcp__dotclaw__list_tasks",
@@ -31,11 +33,6 @@
31
33
  "mcp__dotclaw__resume_task",
32
34
  "mcp__dotclaw__cancel_task",
33
35
  "mcp__dotclaw__update_task",
34
- "mcp__dotclaw__spawn_job",
35
- "mcp__dotclaw__job_status",
36
- "mcp__dotclaw__list_jobs",
37
- "mcp__dotclaw__cancel_job",
38
- "mcp__dotclaw__job_update",
39
36
  "mcp__dotclaw__register_group",
40
37
  "mcp__dotclaw__remove_group",
41
38
  "mcp__dotclaw__list_groups",
@@ -54,15 +51,5 @@
54
51
  "WebFetch": 60
55
52
  },
56
53
  "default_max_per_run": 256
57
- },
58
- "groups": {
59
- "main": {
60
- "allow": ["Bash", "WebSearch", "WebFetch"]
61
- }
62
- },
63
- "users": {
64
- "123456789": {
65
- "deny": ["Bash"]
66
- }
67
54
  }
68
55
  }
@@ -37,6 +37,7 @@ RUN apt-get update && apt-get install -y \
37
37
  tree \
38
38
  ripgrep \
39
39
  graphviz \
40
+ poppler-utils \
40
41
  && rm -rf /var/lib/apt/lists/*
41
42
 
42
43
  # Install GitHub CLI (not in standard Debian repos)
@@ -51,7 +52,7 @@ RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
51
52
  RUN echo 'node ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/node && chmod 0440 /etc/sudoers.d/node
52
53
 
53
54
  # Install common Python packages
54
- RUN pip3 install --break-system-packages pandas numpy requests beautifulsoup4 matplotlib Pillow openpyxl pyyaml tabulate chardet
55
+ RUN pip3 install --break-system-packages pandas numpy requests beautifulsoup4 matplotlib Pillow openpyxl pyyaml tabulate chardet pdfminer.six httpx lxml cssselect python-docx python-pptx
55
56
 
56
57
  # Set Chromium path for agent-browser
57
58
  ENV AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/chromium
@@ -60,6 +61,9 @@ ENV PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium
60
61
  # Install agent-browser globally
61
62
  RUN npm install -g agent-browser
62
63
 
64
+ # Enable pnpm via corepack (cross-platform lockfiles)
65
+ RUN corepack enable && corepack prepare pnpm@latest --activate
66
+
63
67
  # Create app directory
64
68
  WORKDIR /app
65
69
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dotclaw-agent-runner",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
5
  "description": "Container-side agent runner for DotClaw",
6
6
  "main": "dist/index.js",
@@ -27,13 +27,19 @@ export type AgentRuntimeConfig = {
27
27
  summaryMaxOutputTokens: number;
28
28
  temperature: number;
29
29
  maxContextMessageTokens: number;
30
+ maxHistoryTurns: number;
31
+ contextPruning: {
32
+ softTrimMaxChars: number;
33
+ softTrimHeadChars: number;
34
+ softTrimTailChars: number;
35
+ keepLastAssistant: number;
36
+ };
30
37
  };
31
38
  memory: {
32
39
  maxResults: number;
33
40
  maxTokens: number;
34
41
  extraction: {
35
42
  enabled: boolean;
36
- async: boolean;
37
43
  maxMessages: number;
38
44
  maxOutputTokens: number;
39
45
  };
@@ -43,26 +49,6 @@ export type AgentRuntimeConfig = {
43
49
  models: {
44
50
  summary: string;
45
51
  memory: string;
46
- planner: string;
47
- responseValidation: string;
48
- toolSummary: string;
49
- };
50
- planner: {
51
- enabled: boolean;
52
- mode: string;
53
- minTokens: number;
54
- triggerRegex: string;
55
- maxOutputTokens: number;
56
- temperature: number;
57
- };
58
- responseValidation: {
59
- enabled: boolean;
60
- maxOutputTokens: number;
61
- temperature: number;
62
- maxRetries: number;
63
- allowToolCalls: boolean;
64
- minPromptTokens: number;
65
- minResponseTokens: number;
66
52
  };
67
53
  tools: {
68
54
  maxToolSteps: number;
@@ -118,6 +104,9 @@ export type AgentRuntimeConfig = {
118
104
  model: string;
119
105
  baseUrl: string;
120
106
  defaultVoice: string;
107
+ provider: 'edge-tts' | 'openai';
108
+ openaiModel: string;
109
+ openaiVoice: string;
121
110
  };
122
111
  browser: {
123
112
  enabled: boolean;
@@ -136,11 +125,19 @@ export type AgentRuntimeConfig = {
136
125
  }>;
137
126
  connectionTimeoutMs: number;
138
127
  };
128
+ reasoning: {
129
+ effort: 'off' | 'low' | 'medium' | 'high';
130
+ };
139
131
  skills: {
140
132
  enabled: boolean;
141
133
  maxSkills: number;
142
134
  maxSummaryChars: number;
143
135
  };
136
+ process: {
137
+ maxSessions: number;
138
+ maxOutputBytes: number;
139
+ defaultTimeoutMs: number;
140
+ };
144
141
  };
145
142
  };
146
143
 
@@ -164,21 +161,27 @@ const DEFAULT_AGENT_CONFIG: AgentRuntimeConfig['agent'] = {
164
161
  canaryRate: 0.1
165
162
  },
166
163
  context: {
167
- maxContextTokens: 24_000,
168
- compactionTriggerTokens: 20_000,
164
+ maxContextTokens: 128_000,
165
+ compactionTriggerTokens: 120_000,
169
166
  recentContextTokens: 8000,
170
167
  summaryUpdateEveryMessages: 20,
171
- maxOutputTokens: 1024,
168
+ maxOutputTokens: 8192,
172
169
  summaryMaxOutputTokens: 2048,
173
- temperature: 0.2,
174
- maxContextMessageTokens: 3000
170
+ temperature: 0.6,
171
+ maxContextMessageTokens: 4000,
172
+ maxHistoryTurns: 40,
173
+ contextPruning: {
174
+ softTrimMaxChars: 4_000,
175
+ softTrimHeadChars: 1_500,
176
+ softTrimTailChars: 1_500,
177
+ keepLastAssistant: 3
178
+ }
175
179
  },
176
180
  memory: {
177
181
  maxResults: 6,
178
182
  maxTokens: 2000,
179
183
  extraction: {
180
184
  enabled: true,
181
- async: true,
182
185
  maxMessages: 4,
183
186
  maxOutputTokens: 1024
184
187
  },
@@ -187,30 +190,10 @@ const DEFAULT_AGENT_CONFIG: AgentRuntimeConfig['agent'] = {
187
190
  },
188
191
  models: {
189
192
  summary: 'deepseek/deepseek-v3.2',
190
- memory: 'deepseek/deepseek-v3.2',
191
- planner: 'deepseek/deepseek-v3.2',
192
- responseValidation: 'deepseek/deepseek-v3.2',
193
- toolSummary: 'deepseek/deepseek-v3.2'
194
- },
195
- planner: {
196
- enabled: true,
197
- mode: 'auto',
198
- minTokens: 800,
199
- triggerRegex: '(plan|steps|roadmap|research|design|architecture|spec|strategy)',
200
- maxOutputTokens: 1024,
201
- temperature: 0.2
202
- },
203
- responseValidation: {
204
- enabled: true,
205
- maxOutputTokens: 1024,
206
- temperature: 0,
207
- maxRetries: 1,
208
- allowToolCalls: false,
209
- minPromptTokens: 400,
210
- minResponseTokens: 160
193
+ memory: 'deepseek/deepseek-v3.2'
211
194
  },
212
195
  tools: {
213
- maxToolSteps: 96,
196
+ maxToolSteps: 200,
214
197
  outputLimitBytes: 400_000,
215
198
  enableBash: true,
216
199
  enableWebSearch: true,
@@ -226,7 +209,7 @@ const DEFAULT_AGENT_CONFIG: AgentRuntimeConfig['agent'] = {
226
209
  timeoutMs: 20_000
227
210
  },
228
211
  bash: {
229
- timeoutMs: 120_000,
212
+ timeoutMs: 600_000,
230
213
  outputLimitBytes: 200_000
231
214
  },
232
215
  grepMaxFileBytes: 1_000_000,
@@ -262,7 +245,10 @@ const DEFAULT_AGENT_CONFIG: AgentRuntimeConfig['agent'] = {
262
245
  enabled: true,
263
246
  model: 'edge-tts',
264
247
  baseUrl: '',
265
- defaultVoice: 'en-US-AriaNeural'
248
+ defaultVoice: 'en-US-AriaNeural',
249
+ provider: 'edge-tts',
250
+ openaiModel: 'tts-1',
251
+ openaiVoice: 'alloy'
266
252
  },
267
253
  browser: {
268
254
  enabled: true,
@@ -270,18 +256,27 @@ const DEFAULT_AGENT_CONFIG: AgentRuntimeConfig['agent'] = {
270
256
  screenshotQuality: 80
271
257
  },
272
258
  mcp: {
273
- enabled: false,
259
+ enabled: true,
274
260
  servers: [],
275
261
  connectionTimeoutMs: 10_000
276
262
  },
263
+ reasoning: {
264
+ effort: 'medium',
265
+ },
277
266
  skills: {
278
267
  enabled: true,
279
268
  maxSkills: 32,
280
269
  maxSummaryChars: 4000,
270
+ },
271
+ process: {
272
+ maxSessions: 16,
273
+ maxOutputBytes: 1_048_576,
274
+ defaultTimeoutMs: 1_800_000,
281
275
  }
282
276
  };
283
277
 
284
278
  let cachedConfig: AgentRuntimeConfig | null = null;
279
+ let cachedMtime: number | null = null;
285
280
 
286
281
  function cloneConfig<T>(value: T): T {
287
282
  return JSON.parse(JSON.stringify(value)) as T;
@@ -291,20 +286,25 @@ function isPlainObject(value: unknown): value is Record<string, unknown> {
291
286
  return typeof value === 'object' && value !== null && !Array.isArray(value);
292
287
  }
293
288
 
294
- function mergeDefaults<T>(base: T, overrides: unknown): T {
289
+ function mergeDefaults<T>(base: T, overrides: unknown, pathPrefix = ''): T {
295
290
  if (!isPlainObject(overrides)) return cloneConfig(base);
296
291
  const result = cloneConfig(base) as Record<string, unknown>;
297
292
  const baseObj = base as Record<string, unknown>;
298
293
  for (const [key, value] of Object.entries(overrides)) {
299
294
  const current = baseObj[key];
295
+ const fullPath = pathPrefix ? `${pathPrefix}.${key}` : key;
300
296
  if (isPlainObject(current) && isPlainObject(value)) {
301
- result[key] = mergeDefaults(current, value);
297
+ result[key] = mergeDefaults(current, value, fullPath);
302
298
  continue;
303
299
  }
304
300
  if (Array.isArray(current) && Array.isArray(value)) {
305
301
  result[key] = value;
306
302
  continue;
307
303
  }
304
+ if (current !== undefined && typeof value !== typeof current) {
305
+ console.error(`[agent-config] ${fullPath}: expected ${typeof current}, got ${typeof value}. Using default.`);
306
+ continue;
307
+ }
308
308
  if (typeof value === typeof current) {
309
309
  result[key] = value as unknown;
310
310
  }
@@ -325,7 +325,17 @@ function readJson(filePath: string): unknown {
325
325
  }
326
326
 
327
327
  export function loadAgentConfig(): AgentRuntimeConfig {
328
- if (cachedConfig) return cachedConfig;
328
+ if (cachedConfig) {
329
+ // Check if file has been modified since last load
330
+ try {
331
+ const stat = fs.statSync(CONFIG_PATH);
332
+ if (cachedMtime !== null && stat.mtimeMs === cachedMtime) {
333
+ return cachedConfig;
334
+ }
335
+ } catch {
336
+ return cachedConfig;
337
+ }
338
+ }
329
339
  const raw = readJson(CONFIG_PATH);
330
340
 
331
341
  let defaultModel = DEFAULT_DEFAULT_MODEL;
@@ -360,5 +370,11 @@ export function loadAgentConfig(): AgentRuntimeConfig {
360
370
  daemonHeartbeatIntervalMs,
361
371
  agent: mergeDefaults(DEFAULT_AGENT_CONFIG, agentOverrides)
362
372
  };
373
+ try {
374
+ const stat = fs.statSync(CONFIG_PATH);
375
+ cachedMtime = stat.mtimeMs;
376
+ } catch {
377
+ cachedMtime = null;
378
+ }
363
379
  return cachedConfig;
364
380
  }
@@ -8,10 +8,7 @@ export interface ContainerInput {
8
8
  chatJid: string;
9
9
  isMain: boolean;
10
10
  isScheduledTask?: boolean;
11
- isBackgroundTask?: boolean;
12
- isBackgroundJob?: boolean;
13
11
  taskId?: string;
14
- jobId?: string;
15
12
  userId?: string;
16
13
  userName?: string;
17
14
  maxToolSteps?: number;
@@ -37,16 +34,18 @@ export interface ContainerInput {
37
34
  behaviorConfig?: Record<string, unknown>;
38
35
  toolPolicy?: Record<string, unknown>;
39
36
  modelOverride?: string;
37
+ modelFallbacks?: string[];
38
+ reasoningEffort?: 'off' | 'low' | 'medium' | 'high';
39
+ modelCapabilities?: {
40
+ context_length: number;
41
+ max_completion_tokens?: number;
42
+ };
40
43
  modelContextTokens?: number;
41
44
  modelMaxOutputTokens?: number;
42
45
  modelTemperature?: number;
43
46
  timezone?: string;
44
47
  hostPlatform?: string;
45
- disablePlanner?: boolean;
46
- disableResponseValidation?: boolean;
47
- responseValidationMaxRetries?: number;
48
- disableMemoryExtraction?: boolean;
49
- profile?: 'fast' | 'standard' | 'deep' | 'background';
48
+ streamDir?: string;
50
49
  attachments?: Array<{
51
50
  type: 'photo' | 'document' | 'voice' | 'video' | 'audio';
52
51
  path: string;
@@ -76,8 +75,6 @@ export interface ContainerOutput {
76
75
  memory_items_upserted?: number;
77
76
  memory_items_extracted?: number;
78
77
  timings?: {
79
- planner_ms?: number;
80
- response_validation_ms?: number;
81
78
  memory_extraction_ms?: number;
82
79
  tool_ms?: number;
83
80
  };
@@ -91,6 +88,8 @@ export interface ContainerOutput {
91
88
  output_truncated?: boolean;
92
89
  }>;
93
90
  latency_ms?: number;
91
+ /** Reply-to message ID parsed from agent output [[reply_to:<id>]] tags */
92
+ replyToId?: string;
94
93
  /** Set by the host container-runner when stdout was truncated before parsing */
95
94
  stdoutTruncated?: boolean;
96
95
  }