@curie-agent/daemon 0.2.5 → 0.3.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.
- package/dist/src/approval-tracker.d.ts +2 -1
- package/dist/src/approval-tracker.d.ts.map +1 -1
- package/dist/src/approval-tracker.js +14 -5
- package/dist/src/approval-tracker.js.map +1 -1
- package/dist/src/auth.d.ts +3 -4
- package/dist/src/auth.d.ts.map +1 -1
- package/dist/src/auth.js +31 -15
- package/dist/src/auth.js.map +1 -1
- package/dist/src/channel-manager.d.ts.map +1 -1
- package/dist/src/channel-manager.js +4 -2
- package/dist/src/channel-manager.js.map +1 -1
- package/dist/src/daemon-app.d.ts.map +1 -1
- package/dist/src/daemon-app.js +29 -15
- package/dist/src/daemon-app.js.map +1 -1
- package/dist/src/jsonrpc-handler.d.ts.map +1 -1
- package/dist/src/jsonrpc-handler.js +195 -59
- package/dist/src/jsonrpc-handler.js.map +1 -1
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +4 -3
- package/dist/src/server.js.map +1 -1
- package/dist/src/ws-handler.js +1 -1
- package/dist/src/ws-handler.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -5
|
@@ -2,7 +2,7 @@ import os, { homedir } from 'node:os';
|
|
|
2
2
|
import path, { join } from 'node:path';
|
|
3
3
|
import { readFileSync, existsSync, readdirSync, statSync, writeFileSync, mkdirSync, realpathSync } from 'node:fs';
|
|
4
4
|
import { Method } from '@curie-agent/protocol';
|
|
5
|
-
import { TurnLoop, parseReminderTime, listSnapshots, revertTo,
|
|
5
|
+
import { TurnLoop, parseReminderTime, listSnapshots, revertTo, createIdentityFilesAuto } from '@curie-agent/core';
|
|
6
6
|
import { listSkills, discoverAllSkills } from '@curie-agent/tools';
|
|
7
7
|
import { executeCd } from './slash-cd.js';
|
|
8
8
|
export class JsonRpcHandler {
|
|
@@ -199,7 +199,7 @@ export class JsonRpcHandler {
|
|
|
199
199
|
break;
|
|
200
200
|
}
|
|
201
201
|
if (text.startsWith('/')) {
|
|
202
|
-
const targetSessionId = sessionId || this.sessionStore.create(process.cwd(), this.settingsManager.
|
|
202
|
+
const targetSessionId = sessionId || this.sessionStore.create(process.cwd(), this.settingsManager.getActiveModel(), this.settingsManager.get().current_provider || 'unknown', type || 'webui').id;
|
|
203
203
|
// Wait 150ms to guarantee that the client has completed the HTTP roundtrip,
|
|
204
204
|
// received the sessionId, and successfully subscribed to WebSocket events
|
|
205
205
|
// before any synchronous slash command output is emitted.
|
|
@@ -216,7 +216,7 @@ export class JsonRpcHandler {
|
|
|
216
216
|
// The turn loop runs asynchronously in the background.
|
|
217
217
|
if (!sessionId) {
|
|
218
218
|
const settings = this.settingsManager.get();
|
|
219
|
-
const session = this.sessionStore.create(process.cwd(), settings.
|
|
219
|
+
const session = this.sessionStore.create(process.cwd(), settings.providers[settings.current_provider]?.model || settings.model, settings.current_provider || 'unknown', type || 'webui');
|
|
220
220
|
// Start turn loop in background — events stream via WS
|
|
221
221
|
if (this.daemonApp) {
|
|
222
222
|
this.daemonApp.channelManager.send(session.id, text, undefined, type || 'webui').then(res => {
|
|
@@ -412,7 +412,7 @@ export class JsonRpcHandler {
|
|
|
412
412
|
if (!message || !scheduledAt)
|
|
413
413
|
return this.paramError('message, scheduledAt');
|
|
414
414
|
if (this.daemonApp) {
|
|
415
|
-
const mode = type === 'task' ? '
|
|
415
|
+
const mode = type === 'task' ? 'agent' : 'notify';
|
|
416
416
|
const task = this.daemonApp.taskManager.create({ title: message, mode, scope: 'personal', scheduled_at: scheduledAt });
|
|
417
417
|
result = task;
|
|
418
418
|
}
|
|
@@ -488,7 +488,7 @@ export class JsonRpcHandler {
|
|
|
488
488
|
const userName = this.getStringParam(p, 'userName') || 'User';
|
|
489
489
|
const userTimezone = this.getStringParam(p, 'userTimezone') || 'UTC';
|
|
490
490
|
const userLanguages = this.getStringParam(p, 'userLanguages') || 'TypeScript, Python';
|
|
491
|
-
|
|
491
|
+
createIdentityFilesAuto({
|
|
492
492
|
provider: provider,
|
|
493
493
|
apiKey,
|
|
494
494
|
model,
|
|
@@ -509,7 +509,6 @@ export class JsonRpcHandler {
|
|
|
509
509
|
settings.current_provider = provider;
|
|
510
510
|
settings.model = model;
|
|
511
511
|
this.settingsManager.update(settings);
|
|
512
|
-
this.settingsManager.save();
|
|
513
512
|
this.sharedEventBus?.emit({
|
|
514
513
|
type: 'config-changed',
|
|
515
514
|
id: Math.random().toString(36).substring(7),
|
|
@@ -517,16 +516,58 @@ export class JsonRpcHandler {
|
|
|
517
516
|
key: 'init',
|
|
518
517
|
value: true,
|
|
519
518
|
});
|
|
520
|
-
result = { status: 'complete', files: ['SOUL.md', 'USER.md', 'AGENTS.md', 'MEMORY.md', 'TOOLS.md', 'HEARTBEAT.md'] };
|
|
519
|
+
result = { status: 'complete', files: ['SOUL.md', 'USER.md', 'AGENTS.md', 'MEMORY.md', 'TOOLS.md', 'HEARTBEAT.md'], skills: ['deep-research', 'planning'] };
|
|
521
520
|
break;
|
|
522
521
|
}
|
|
523
522
|
// Not yet implemented
|
|
524
523
|
case Method.ORCHESTRA_PANES:
|
|
525
524
|
case Method.ORCHESTRA_BROADCAST:
|
|
526
|
-
case Method.WIKI_QUERY:
|
|
527
|
-
case Method.WIKI_PAGE_GET:
|
|
528
525
|
result = { status: 'not-implemented', method };
|
|
529
526
|
break;
|
|
527
|
+
// Wiki operations
|
|
528
|
+
case Method.WIKI_QUERY: {
|
|
529
|
+
const { WikiManager } = await import('@curie-agent/wiki');
|
|
530
|
+
const query = this.getStringParam(params, 'query');
|
|
531
|
+
if (!query)
|
|
532
|
+
return this.paramError('query');
|
|
533
|
+
const wm = new WikiManager(this.settingsManager.get());
|
|
534
|
+
wm.ensureStructure();
|
|
535
|
+
result = wm.search(query);
|
|
536
|
+
break;
|
|
537
|
+
}
|
|
538
|
+
case Method.WIKI_PAGE_GET: {
|
|
539
|
+
const { WikiManager } = await import('@curie-agent/wiki');
|
|
540
|
+
const slug = this.getStringParam(params, 'slug');
|
|
541
|
+
if (!slug)
|
|
542
|
+
return this.paramError('slug');
|
|
543
|
+
const wm = new WikiManager(this.settingsManager.get());
|
|
544
|
+
wm.ensureStructure();
|
|
545
|
+
const content = wm.readPage(slug);
|
|
546
|
+
result = content !== null ? { slug, content } : { error: `Page not found: ${slug}` };
|
|
547
|
+
break;
|
|
548
|
+
}
|
|
549
|
+
case Method.WIKI_INGEST: {
|
|
550
|
+
const { WikiManager } = await import('@curie-agent/wiki');
|
|
551
|
+
const wm = new WikiManager(this.settingsManager.get());
|
|
552
|
+
wm.ensureStructure();
|
|
553
|
+
const pages = wm.listPages();
|
|
554
|
+
result = { pages, index: wm.readIndex() };
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
case Method.WIKI_LINT: {
|
|
558
|
+
const { WikiManager } = await import('@curie-agent/wiki');
|
|
559
|
+
const wm = new WikiManager(this.settingsManager.get());
|
|
560
|
+
wm.ensureStructure();
|
|
561
|
+
result = wm.lintReport();
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
case Method.WIKI_GRAPH: {
|
|
565
|
+
const { WikiManager } = await import('@curie-agent/wiki');
|
|
566
|
+
const wm = new WikiManager(this.settingsManager.get());
|
|
567
|
+
wm.ensureStructure();
|
|
568
|
+
result = wm.graph();
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
530
571
|
// Subagent management
|
|
531
572
|
case Method.SUBAGENT_SPAWN: {
|
|
532
573
|
const p = params;
|
|
@@ -550,17 +591,12 @@ export class JsonRpcHandler {
|
|
|
550
591
|
const providerInstance = this.createProvider(spawnSettings);
|
|
551
592
|
// Resolve model for the subagent.
|
|
552
593
|
// - Explicit 'model' param from UI always wins.
|
|
553
|
-
// -
|
|
554
|
-
// - If same provider as parent, inherit model_override if set.
|
|
594
|
+
// - Otherwise use the target provider's configured model.
|
|
555
595
|
const effectiveModel = (() => {
|
|
556
596
|
if (model)
|
|
557
597
|
return model;
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
return spawnSettings.providers?.[providerName]?.model || settings.model;
|
|
561
|
-
}
|
|
562
|
-
// Same provider — allow model_override to apply
|
|
563
|
-
return spawnSettings.model_override || spawnSettings.model;
|
|
598
|
+
const targetProvider = spawnSettings.providers?.[providerName || spawnSettings.current_provider];
|
|
599
|
+
return targetProvider?.model || spawnSettings.model;
|
|
564
600
|
})();
|
|
565
601
|
const handle = await this.daemonApp.subagentExecutor.spawn({
|
|
566
602
|
provider: providerInstance,
|
|
@@ -691,7 +727,7 @@ export class JsonRpcHandler {
|
|
|
691
727
|
this.daemonApp.taskManager.load();
|
|
692
728
|
const task = this.daemonApp.taskManager.create({
|
|
693
729
|
title: instruction,
|
|
694
|
-
mode: '
|
|
730
|
+
mode: 'agent',
|
|
695
731
|
scope: 'personal',
|
|
696
732
|
scheduled_at: scheduledAtMs,
|
|
697
733
|
description: Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : '',
|
|
@@ -705,6 +741,99 @@ export class JsonRpcHandler {
|
|
|
705
741
|
};
|
|
706
742
|
break;
|
|
707
743
|
}
|
|
744
|
+
// ---- Unified task (todo) management for Kanban board ----
|
|
745
|
+
case Method.TODO_LIST: {
|
|
746
|
+
if (!this.daemonApp) {
|
|
747
|
+
return { jsonrpc: '2.0', id, error: { code: -32603, message: 'Daemon not initialized' } };
|
|
748
|
+
}
|
|
749
|
+
this.daemonApp.taskManager.load();
|
|
750
|
+
const p = (params || {});
|
|
751
|
+
const filters = {};
|
|
752
|
+
if (typeof p.status === 'string')
|
|
753
|
+
filters.status = p.status;
|
|
754
|
+
if (typeof p.mode === 'string')
|
|
755
|
+
filters.mode = p.mode;
|
|
756
|
+
if (typeof p.scope === 'string')
|
|
757
|
+
filters.scope = p.scope;
|
|
758
|
+
if (typeof p.priority === 'string')
|
|
759
|
+
filters.priority = p.priority;
|
|
760
|
+
result = this.daemonApp.taskManager.list(Object.keys(filters).length ? filters : undefined);
|
|
761
|
+
break;
|
|
762
|
+
}
|
|
763
|
+
case Method.TODO_CREATE: {
|
|
764
|
+
if (!this.daemonApp) {
|
|
765
|
+
return { jsonrpc: '2.0', id, error: { code: -32603, message: 'Daemon not initialized' } };
|
|
766
|
+
}
|
|
767
|
+
this.daemonApp.taskManager.load();
|
|
768
|
+
const p = params;
|
|
769
|
+
const title = this.getStringParam(p, 'title') || '';
|
|
770
|
+
if (!title)
|
|
771
|
+
return this.paramError('title');
|
|
772
|
+
const task = this.daemonApp.taskManager.create({
|
|
773
|
+
title,
|
|
774
|
+
description: this.getStringParam(p, 'description'),
|
|
775
|
+
mode: typeof p.mode === 'string' ? p.mode : 'human',
|
|
776
|
+
scope: typeof p.scope === 'string' ? p.scope : 'personal',
|
|
777
|
+
priority: typeof p.priority === 'string' ? p.priority : 'medium',
|
|
778
|
+
tags: Array.isArray(p.tags) ? p.tags : [],
|
|
779
|
+
scheduled_at: typeof p.scheduled_at === 'number' ? p.scheduled_at : undefined,
|
|
780
|
+
});
|
|
781
|
+
// Override status if specified (create() sets default based on mode)
|
|
782
|
+
if (typeof p.status === 'string') {
|
|
783
|
+
this.daemonApp.taskManager.updateTaskStatus(task.id, p.status);
|
|
784
|
+
}
|
|
785
|
+
this.sharedEventBus?.emit({ type: 'todo-changed', id: crypto.randomUUID(), timestamp: Date.now(), action: 'created', taskId: task.id });
|
|
786
|
+
result = this.daemonApp.taskManager.findTask(task.id);
|
|
787
|
+
break;
|
|
788
|
+
}
|
|
789
|
+
case Method.TODO_UPDATE: {
|
|
790
|
+
if (!this.daemonApp) {
|
|
791
|
+
return { jsonrpc: '2.0', id, error: { code: -32603, message: 'Daemon not initialized' } };
|
|
792
|
+
}
|
|
793
|
+
this.daemonApp.taskManager.load();
|
|
794
|
+
const p = params;
|
|
795
|
+
const taskId = this.getStringParam(p, 'id');
|
|
796
|
+
if (!taskId)
|
|
797
|
+
return this.paramError('id');
|
|
798
|
+
const task = this.daemonApp.taskManager.findTask(taskId);
|
|
799
|
+
if (!task)
|
|
800
|
+
return { jsonrpc: '2.0', id, error: { code: -32602, message: `Task ${taskId} not found` } };
|
|
801
|
+
if (typeof p.status === 'string') {
|
|
802
|
+
this.daemonApp.taskManager.updateTaskStatus(taskId, p.status);
|
|
803
|
+
}
|
|
804
|
+
if (typeof p.priority === 'string')
|
|
805
|
+
task.priority = p.priority;
|
|
806
|
+
if (typeof p.title === 'string')
|
|
807
|
+
task.title = p.title;
|
|
808
|
+
if (typeof p.description === 'string')
|
|
809
|
+
task.description = p.description;
|
|
810
|
+
if (Array.isArray(p.tags))
|
|
811
|
+
task.tags = p.tags;
|
|
812
|
+
if (typeof p.mode === 'string')
|
|
813
|
+
task.mode = p.mode;
|
|
814
|
+
if (typeof p.scope === 'string')
|
|
815
|
+
task.scope = p.scope;
|
|
816
|
+
if (typeof p.scheduled_at === 'number')
|
|
817
|
+
task.scheduled_at = p.scheduled_at;
|
|
818
|
+
this.daemonApp.taskManager.save();
|
|
819
|
+
this.sharedEventBus?.emit({ type: 'todo-changed', id: crypto.randomUUID(), timestamp: Date.now(), action: 'updated', taskId });
|
|
820
|
+
result = { ok: true, task: this.daemonApp.taskManager.findTask(taskId) };
|
|
821
|
+
break;
|
|
822
|
+
}
|
|
823
|
+
case Method.TODO_REMOVE: {
|
|
824
|
+
if (!this.daemonApp) {
|
|
825
|
+
return { jsonrpc: '2.0', id, error: { code: -32603, message: 'Daemon not initialized' } };
|
|
826
|
+
}
|
|
827
|
+
this.daemonApp.taskManager.load();
|
|
828
|
+
const p = params;
|
|
829
|
+
const taskId = this.getStringParam(p, 'id');
|
|
830
|
+
if (!taskId)
|
|
831
|
+
return this.paramError('id');
|
|
832
|
+
const removed = this.daemonApp.taskManager.removeTask(taskId);
|
|
833
|
+
this.sharedEventBus?.emit({ type: 'todo-changed', id: crypto.randomUUID(), timestamp: Date.now(), action: 'removed', taskId });
|
|
834
|
+
result = { removed };
|
|
835
|
+
break;
|
|
836
|
+
}
|
|
708
837
|
default:
|
|
709
838
|
return { jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } };
|
|
710
839
|
}
|
|
@@ -731,7 +860,7 @@ export class JsonRpcHandler {
|
|
|
731
860
|
// Build the turn loop config
|
|
732
861
|
const loop = new TurnLoop({
|
|
733
862
|
provider,
|
|
734
|
-
model: settings.
|
|
863
|
+
model: settings.providers[settings.current_provider]?.model || settings.model,
|
|
735
864
|
tools: this.tools,
|
|
736
865
|
cwd: sessionInfo?.cwd || join(homedir(), '.curie-agent'),
|
|
737
866
|
settings,
|
|
@@ -744,11 +873,13 @@ export class JsonRpcHandler {
|
|
|
744
873
|
}, this.sessionStore);
|
|
745
874
|
// Store the loop for potential cancellation
|
|
746
875
|
this.turnLoops.set(sessionId, loop);
|
|
747
|
-
// Bridge the turn loop's event bus to the shared daemon event bus
|
|
748
|
-
//
|
|
876
|
+
// Bridge the turn loop's event bus to the shared daemon event bus.
|
|
877
|
+
// Note: 'approval-request' is NOT bridged — ApprovalTracker.register()
|
|
878
|
+
// emits it directly. In direct mode (no daemonApp), approval events
|
|
879
|
+
// are not tracked externally anyway.
|
|
749
880
|
const eventTypes = [
|
|
750
881
|
'user-prompt', 'assistant-delta', 'assistant-stop', 'tool-call',
|
|
751
|
-
'tool-result', 'approval-
|
|
882
|
+
'tool-result', 'approval-decision', 'usage',
|
|
752
883
|
'error', 'session-start', 'session-stop', 'hook', 'status',
|
|
753
884
|
'session-resumed', 'context-warning', 'thinking-delta',
|
|
754
885
|
// Subagent events
|
|
@@ -953,7 +1084,7 @@ Usage: \`/model window <tokens>\` (e.g., \`/model window 120000\`).`);
|
|
|
953
1084
|
}
|
|
954
1085
|
}
|
|
955
1086
|
else {
|
|
956
|
-
|
|
1087
|
+
pConfig.model = args;
|
|
957
1088
|
settings.model = args;
|
|
958
1089
|
this.settingsManager.update(settings);
|
|
959
1090
|
this.sharedEventBus?.emit({
|
|
@@ -980,9 +1111,7 @@ Usage: \`/model window <tokens>\` (e.g., \`/model window 120000\`).`);
|
|
|
980
1111
|
emitDelta(`Unknown provider: "${args}". Valid options are: ${valid.join(', ')}`);
|
|
981
1112
|
}
|
|
982
1113
|
else {
|
|
983
|
-
|
|
984
|
-
settings.model_override = undefined;
|
|
985
|
-
this.settingsManager.update(settings);
|
|
1114
|
+
this.settingsManager.setCurrentProvider(provider);
|
|
986
1115
|
this.sharedEventBus?.emit({
|
|
987
1116
|
type: 'config-changed',
|
|
988
1117
|
id: Math.random().toString(36).substring(7),
|
|
@@ -1303,29 +1432,40 @@ Usage: \`/model window <tokens>\` (e.g., \`/model window 120000\`).`);
|
|
|
1303
1432
|
? activeLoop.eventBus.history()
|
|
1304
1433
|
: (this.sessionStore.loadEvents(sessionId) || []);
|
|
1305
1434
|
const usageEvents = history.filter((e) => e.type === 'usage');
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
input += e.inputTokens || 0;
|
|
1310
|
-
output += e.outputTokens || 0;
|
|
1311
|
-
}
|
|
1435
|
+
const latestUsage = usageEvents[usageEvents.length - 1];
|
|
1436
|
+
const input = latestUsage ? (latestUsage.inputTokens || 0) : 0;
|
|
1437
|
+
const output = latestUsage ? (latestUsage.outputTokens || 0) : 0;
|
|
1312
1438
|
const model = settings.model || 'unknown';
|
|
1313
1439
|
const windowSize = settings.providers?.[settings.current_provider]?.model_context_window ?? 200000;
|
|
1314
1440
|
const pct = input > 0 ? Math.min(100, Math.round((input / windowSize) * 100)) : 0;
|
|
1315
|
-
const
|
|
1316
|
-
|
|
1317
|
-
|
|
1441
|
+
const fmt = (n) => {
|
|
1442
|
+
if (n >= 1_000_000)
|
|
1443
|
+
return `${(n / 1_000_000).toFixed(1)}m`;
|
|
1444
|
+
if (n >= 1_000)
|
|
1445
|
+
return `${(n / 1_000).toFixed(1)}k`;
|
|
1446
|
+
return String(n);
|
|
1447
|
+
};
|
|
1318
1448
|
if (input === 0 && output === 0) {
|
|
1319
1449
|
emitDelta(`No token data yet. Start a conversation to see context window usage.\n\nActive model: \`${model}\` (Max Context: \`${fmt(windowSize)}\` tokens).`);
|
|
1320
1450
|
}
|
|
1321
1451
|
else {
|
|
1322
|
-
const
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
emitDelta(
|
|
1452
|
+
const barColor = pct > 80 ? 'var(--red)' : pct > 50 ? 'var(--yellow)' : 'var(--green)';
|
|
1453
|
+
const barGradient = pct > 80
|
|
1454
|
+
? 'linear-gradient(90deg, var(--red), #e08070)'
|
|
1455
|
+
: pct > 50
|
|
1456
|
+
? 'linear-gradient(90deg, var(--yellow), #f0d090)'
|
|
1457
|
+
: 'linear-gradient(90deg, var(--green), #c0d8a8)';
|
|
1458
|
+
emitDelta(`<div style="background:var(--s3);border-radius:8px;padding:12px;margin:8px 0">` +
|
|
1459
|
+
`<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">` +
|
|
1460
|
+
`<span style="font-family:monospace;font-size:12px;color:var(--text)">Context Window (${model})</span>` +
|
|
1461
|
+
`<span style="font-family:monospace;font-size:13px;font-weight:bold;color:${barColor}">${pct}%</span>` +
|
|
1462
|
+
`</div>` +
|
|
1463
|
+
`<div style="background:var(--s2);border-radius:4px;height:8px;overflow:hidden">` +
|
|
1464
|
+
`<div style="width:${pct}%;height:100%;background:${barGradient};border-radius:4px"></div>` +
|
|
1465
|
+
`</div>` +
|
|
1466
|
+
`<div style="display:flex;justify-content:space-between;margin-top:8px;font-family:monospace;font-size:11px;color:var(--muted)">` +
|
|
1467
|
+
`<span>In: ${fmt(input)}</span><span>Out: ${fmt(output)}</span><span>Max: ${fmt(windowSize)}</span>` +
|
|
1468
|
+
`</div></div>`);
|
|
1329
1469
|
}
|
|
1330
1470
|
}
|
|
1331
1471
|
break;
|
|
@@ -1633,7 +1773,7 @@ Usage: \`/model window <tokens>\` (e.g., \`/model window 120000\`).`);
|
|
|
1633
1773
|
emitDelta(`Could not parse scheduled time from: "${rest}". Try: \`at 7:55 do something\` or \`tomorrow at 9am do something\`.`);
|
|
1634
1774
|
}
|
|
1635
1775
|
else {
|
|
1636
|
-
const task = this.daemonApp.taskManager.create({ title: parsed.message, mode: '
|
|
1776
|
+
const task = this.daemonApp.taskManager.create({ title: parsed.message, mode: 'agent', scope: 'personal', scheduled_at: parsed.scheduledAt });
|
|
1637
1777
|
const timeStr = new Date(task.scheduled_at).toLocaleString();
|
|
1638
1778
|
emitDelta(`### Task Scheduled Successfully!
|
|
1639
1779
|
* **Task ID**: \`${task.id}\`
|
|
@@ -1647,7 +1787,7 @@ Usage: \`/model window <tokens>\` (e.g., \`/model window 120000\`).`);
|
|
|
1647
1787
|
const filter = ['pending', 'executing', 'completed', 'failed', 'cancelled'].includes(rest.toLowerCase())
|
|
1648
1788
|
? rest.toLowerCase()
|
|
1649
1789
|
: undefined;
|
|
1650
|
-
const tasks = this.daemonApp.taskManager.list({ mode: '
|
|
1790
|
+
const tasks = this.daemonApp.taskManager.list({ mode: 'agent' });
|
|
1651
1791
|
if (tasks.length === 0) {
|
|
1652
1792
|
emitDelta(filter ? `No tasks found with status **${filter}**.` : `No tasks scheduled yet. Use \`/task create\` to schedule a task.`);
|
|
1653
1793
|
}
|
|
@@ -1721,7 +1861,7 @@ Usage: \`/model window <tokens>\` (e.g., \`/model window 120000\`).`);
|
|
|
1721
1861
|
const hasAllowlist = raw && (Array.isArray(raw) ? raw.length > 0 : typeof raw === 'string' && raw.trim().length > 0);
|
|
1722
1862
|
const display = Array.isArray(raw) ? raw.join(', ') : raw;
|
|
1723
1863
|
lines.push(`* **Allowlist:** ${hasAllowlist ? `\`${display}\`` : '(empty)'}`);
|
|
1724
|
-
lines.push(`**Blocked:**
|
|
1864
|
+
lines.push(`**Blocked:** \`~/.curie-settings.json\` (API keys)`);
|
|
1725
1865
|
emitDelta(lines.join('\n'));
|
|
1726
1866
|
break;
|
|
1727
1867
|
}
|
|
@@ -1836,7 +1976,7 @@ Usage: \`/model window <tokens>\` (e.g., \`/model window 120000\`).`);
|
|
|
1836
1976
|
const provider = this.createProvider(settings);
|
|
1837
1977
|
const handle = await this.daemonApp.subagentExecutor.spawn({
|
|
1838
1978
|
provider,
|
|
1839
|
-
model: settings.
|
|
1979
|
+
model: settings.providers[settings.current_provider]?.model || settings.model,
|
|
1840
1980
|
tools: this.tools,
|
|
1841
1981
|
cwd: join(homedir(), '.curie-agent'),
|
|
1842
1982
|
settings,
|
|
@@ -1862,11 +2002,11 @@ Usage: \`/model window <tokens>\` (e.g., \`/model window 120000\`).`);
|
|
|
1862
2002
|
const parts = args.trim().split(/\s+/);
|
|
1863
2003
|
const sub = parts[0]?.toLowerCase() || '';
|
|
1864
2004
|
const rest = parts.slice(1).join(' ').trim();
|
|
1865
|
-
// Detect mode keyword (
|
|
2005
|
+
// Detect mode keyword (agent/notify) from full args
|
|
1866
2006
|
const fullArgsLower = args.toLowerCase();
|
|
1867
|
-
let mode = '
|
|
1868
|
-
if (/^
|
|
1869
|
-
mode = '
|
|
2007
|
+
let mode = 'human';
|
|
2008
|
+
if (/^agent\s/.test(fullArgsLower) || /^\bat\b/.test(fullArgsLower)) {
|
|
2009
|
+
mode = 'agent';
|
|
1870
2010
|
}
|
|
1871
2011
|
else if (/^notify\s/.test(fullArgsLower) || /remind\s/.test(fullArgsLower)) {
|
|
1872
2012
|
mode = 'notify';
|
|
@@ -1910,10 +2050,10 @@ Usage: \`/model window <tokens>\` (e.g., \`/model window 120000\`).`);
|
|
|
1910
2050
|
const parsed = parseReminderTime(instruction);
|
|
1911
2051
|
if (parsed) {
|
|
1912
2052
|
instruction = parsed.message;
|
|
1913
|
-
if (mode === '
|
|
2053
|
+
if (mode === 'agent') {
|
|
1914
2054
|
const task = this.daemonApp.taskManager.create({
|
|
1915
2055
|
title: instruction,
|
|
1916
|
-
mode: '
|
|
2056
|
+
mode: 'agent', scope, scheduled_at: parsed.scheduledAt,
|
|
1917
2057
|
});
|
|
1918
2058
|
emitDelta(`**Task scheduled**: "${instruction}" at ${new Date(parsed.scheduledAt).toLocaleString()} (ID: \`${task.id.slice(0, 8)}...\`)`);
|
|
1919
2059
|
}
|
|
@@ -2079,7 +2219,7 @@ Usage: \`/model window <tokens>\` (e.g., \`/model window 120000\`).`);
|
|
|
2079
2219
|
}
|
|
2080
2220
|
const settings = this.settingsManager.get();
|
|
2081
2221
|
const provider = this.createProvider(settings);
|
|
2082
|
-
const model = settings.
|
|
2222
|
+
const model = settings.providers[settings.current_provider]?.model || settings.model;
|
|
2083
2223
|
const events = this.sessionStore.loadEvents(sessionId) || [];
|
|
2084
2224
|
if (events.length === 0) {
|
|
2085
2225
|
throw new Error('No events to compact');
|
|
@@ -2146,12 +2286,8 @@ Usage: \`/model window <tokens>\` (e.g., \`/model window 120000\`).`);
|
|
|
2146
2286
|
const settings = this.settingsManager.get();
|
|
2147
2287
|
const history = this.sessionStore.loadEvents(sessionId) || [];
|
|
2148
2288
|
const usageEvents = history.filter((e) => e.type === 'usage');
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
for (const e of usageEvents) {
|
|
2152
|
-
input += e.inputTokens || 0;
|
|
2153
|
-
output += e.outputTokens || 0;
|
|
2154
|
-
}
|
|
2289
|
+
const latestUsage = usageEvents[usageEvents.length - 1];
|
|
2290
|
+
const input = latestUsage?.inputTokens ?? 0;
|
|
2155
2291
|
if (input === 0)
|
|
2156
2292
|
return; // No token data yet
|
|
2157
2293
|
const windowSize = settings.providers?.[settings.current_provider]?.model_context_window ?? 200000;
|