@kb-labs/agent-entry 2.93.0 → 2.96.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 (79) hide show
  1. package/dist/cli/commands/diff.js +4 -4
  2. package/dist/cli/commands/diff.js.map +1 -1
  3. package/dist/cli/commands/history.js +6 -6
  4. package/dist/cli/commands/history.js.map +1 -1
  5. package/dist/cli/commands/quality-report.js +3 -3
  6. package/dist/cli/commands/quality-report.js.map +1 -1
  7. package/dist/cli/commands/rollback.js +1 -1
  8. package/dist/cli/commands/rollback.js.map +1 -1
  9. package/dist/cli/commands/run.js +24 -7
  10. package/dist/cli/commands/run.js.map +1 -1
  11. package/dist/cli/commands/trace-context.js +3 -3
  12. package/dist/cli/commands/trace-context.js.map +1 -1
  13. package/dist/cli/commands/trace-diagnose.js +3 -3
  14. package/dist/cli/commands/trace-diagnose.js.map +1 -1
  15. package/dist/cli/commands/trace-stats.js +3 -3
  16. package/dist/cli/commands/trace-stats.js.map +1 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +40 -35
  19. package/dist/index.js.map +1 -1
  20. package/dist/manifest.d.ts +62 -7
  21. package/dist/manifest.js +40 -35
  22. package/dist/manifest.js.map +1 -1
  23. package/dist/rest/handlers/approve-handler.js +51 -47
  24. package/dist/rest/handlers/approve-handler.js.map +1 -1
  25. package/dist/rest/handlers/approve-session-plan-handler.js +38 -34
  26. package/dist/rest/handlers/approve-session-plan-handler.js.map +1 -1
  27. package/dist/rest/handlers/correct-handler.js +49 -45
  28. package/dist/rest/handlers/correct-handler.js.map +1 -1
  29. package/dist/rest/handlers/create-session-handler.js +17 -13
  30. package/dist/rest/handlers/create-session-handler.js.map +1 -1
  31. package/dist/rest/handlers/execute-session-plan-handler.js +216 -208
  32. package/dist/rest/handlers/execute-session-plan-handler.js.map +1 -1
  33. package/dist/rest/handlers/generate-spec-handler.js +103 -98
  34. package/dist/rest/handlers/generate-spec-handler.js.map +1 -1
  35. package/dist/rest/handlers/get-file-diff-handler.js +35 -31
  36. package/dist/rest/handlers/get-file-diff-handler.js.map +1 -1
  37. package/dist/rest/handlers/get-session-handler.js +15 -11
  38. package/dist/rest/handlers/get-session-handler.js.map +1 -1
  39. package/dist/rest/handlers/get-session-plan-handler.js +28 -24
  40. package/dist/rest/handlers/get-session-plan-handler.js.map +1 -1
  41. package/dist/rest/handlers/get-session-turns-handler.js +27 -23
  42. package/dist/rest/handlers/get-session-turns-handler.js.map +1 -1
  43. package/dist/rest/handlers/get-spec-handler.js +22 -18
  44. package/dist/rest/handlers/get-spec-handler.js.map +1 -1
  45. package/dist/rest/handlers/list-file-changes-handler.js +25 -21
  46. package/dist/rest/handlers/list-file-changes-handler.js.map +1 -1
  47. package/dist/rest/handlers/list-sessions-handler.js +16 -12
  48. package/dist/rest/handlers/list-sessions-handler.js.map +1 -1
  49. package/dist/rest/handlers/rollback-handler.js +73 -69
  50. package/dist/rest/handlers/rollback-handler.js.map +1 -1
  51. package/dist/rest/handlers/run-handler.js +151 -147
  52. package/dist/rest/handlers/run-handler.js.map +1 -1
  53. package/dist/rest/handlers/sessions-handler.js +47 -35
  54. package/dist/rest/handlers/sessions-handler.js.map +1 -1
  55. package/dist/rest/handlers/status-handler.js +33 -29
  56. package/dist/rest/handlers/status-handler.js.map +1 -1
  57. package/dist/rest/handlers/stop-handler.js +37 -33
  58. package/dist/rest/handlers/stop-handler.js.map +1 -1
  59. package/dist/widgets/117.js +24 -1
  60. package/dist/widgets/{300.js → 215.js} +1 -1
  61. package/dist/widgets/370.js +1 -1
  62. package/dist/widgets/{805.js → 46.js} +92 -92
  63. package/dist/widgets/50.js +1 -1
  64. package/dist/widgets/62.js +96 -0
  65. package/dist/widgets/648.js +1 -0
  66. package/dist/widgets/669.js +1 -1
  67. package/dist/widgets/775.js +1 -1
  68. package/dist/widgets/78.js +1 -0
  69. package/dist/widgets/968.js +2 -2
  70. package/dist/widgets/__federation_expose_AgentsPage.js +1 -1
  71. package/dist/widgets/mf-manifest.json +31 -31
  72. package/dist/widgets/mf-stats.json +39 -39
  73. package/dist/widgets/remoteEntry.js +2 -2
  74. package/dist/ws/session-stream-handler.js +17 -6
  75. package/dist/ws/session-stream-handler.js.map +1 -1
  76. package/package.json +16 -15
  77. package/dist/widgets/418.js +0 -38
  78. package/dist/widgets/451.js +0 -1
  79. package/dist/widgets/694.js +0 -1
@@ -1,4 +1,4 @@
1
- import { defineHandler } from '@kb-labs/sdk';
1
+ import { defineHandler, rethrowForRest } from '@kb-labs/sdk';
2
2
  import { SessionManager } from '@kb-labs/agent-core';
3
3
  import { ChangeStore } from '@kb-labs/agent-history';
4
4
  import { promises } from 'fs';
@@ -7,82 +7,86 @@ import path from 'path';
7
7
  // src/rest/handlers/rollback-handler.ts
8
8
  var rollback_handler_default = defineHandler({
9
9
  async execute(ctx, input) {
10
- const params = input.params;
11
- const sessionId = params?.sessionId;
12
- if (!sessionId) {
13
- throw new Error("Session ID is required");
14
- }
15
- const body = input.body ?? {};
16
- const sessionManager = new SessionManager(ctx.cwd);
17
- const session = await sessionManager.loadSession(sessionId);
18
- if (!session) {
19
- throw new Error(`Session not found: ${sessionId}`);
20
- }
21
- const workingDir = session.workingDir || ctx.cwd;
22
- const store = new ChangeStore(workingDir);
23
- let changes;
24
- if (body.runId) {
25
- changes = await store.listRun(sessionId, body.runId);
26
- } else if (body.changeIds?.length) {
27
- const ids = new Set(body.changeIds);
28
- const all = await store.listSession(sessionId);
29
- changes = all.filter((c) => ids.has(c.id));
30
- } else {
31
- changes = await store.listSession(sessionId);
32
- }
33
- if (changes.length === 0) {
34
- return { rolledBack: 0, skipped: 0, conflicts: [], success: true };
35
- }
36
- const sorted = [...changes].sort(
37
- (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
38
- );
39
- const fullHistory = await store.listSession(sessionId);
40
- const rollbackIds = new Set(sorted.map((c) => c.id));
41
- const conflicts = [];
42
- let rolledBack = 0;
43
- let skipped = 0;
44
- for (const change of sorted) {
45
- if (!body.skipConflicts) {
46
- const laterChanges = fullHistory.filter(
47
- (c) => c.filePath === change.filePath && new Date(c.timestamp).getTime() > new Date(change.timestamp).getTime() && !rollbackIds.has(c.id)
48
- );
49
- if (laterChanges.length > 0) {
50
- const laterAgents = [...new Set(laterChanges.map((c) => c.agentId))].join(", ");
10
+ try {
11
+ const params = input.params;
12
+ const sessionId = params?.sessionId;
13
+ if (!sessionId) {
14
+ throw new Error("Session ID is required");
15
+ }
16
+ const body = input.body ?? {};
17
+ const sessionManager = new SessionManager(ctx.cwd);
18
+ const session = await sessionManager.loadSession(sessionId);
19
+ if (!session) {
20
+ throw new Error(`Session not found: ${sessionId}`);
21
+ }
22
+ const workingDir = session.workingDir || ctx.cwd;
23
+ const store = new ChangeStore(workingDir);
24
+ let changes;
25
+ if (body.runId) {
26
+ changes = await store.listRun(sessionId, body.runId);
27
+ } else if (body.changeIds?.length) {
28
+ const ids = new Set(body.changeIds);
29
+ const all = await store.listSession(sessionId);
30
+ changes = all.filter((c) => ids.has(c.id));
31
+ } else {
32
+ changes = await store.listSession(sessionId);
33
+ }
34
+ if (changes.length === 0) {
35
+ return { rolledBack: 0, skipped: 0, conflicts: [], success: true };
36
+ }
37
+ const sorted = [...changes].sort(
38
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
39
+ );
40
+ const fullHistory = await store.listSession(sessionId);
41
+ const rollbackIds = new Set(sorted.map((c) => c.id));
42
+ const conflicts = [];
43
+ let rolledBack = 0;
44
+ let skipped = 0;
45
+ for (const change of sorted) {
46
+ if (!body.skipConflicts) {
47
+ const laterChanges = fullHistory.filter(
48
+ (c) => c.filePath === change.filePath && new Date(c.timestamp).getTime() > new Date(change.timestamp).getTime() && !rollbackIds.has(c.id)
49
+ );
50
+ if (laterChanges.length > 0) {
51
+ const laterAgents = [...new Set(laterChanges.map((c) => c.agentId))].join(", ");
52
+ conflicts.push({
53
+ filePath: change.filePath,
54
+ changeId: change.id,
55
+ reason: `File was modified after this change by: ${laterAgents}. Use skipConflicts: true to force.`
56
+ });
57
+ skipped++;
58
+ continue;
59
+ }
60
+ }
61
+ const fullPath = path.join(workingDir, change.filePath);
62
+ try {
63
+ if (change.before) {
64
+ await promises.mkdir(path.dirname(fullPath), { recursive: true });
65
+ await promises.writeFile(fullPath, change.before.content, "utf-8");
66
+ } else {
67
+ await promises.unlink(fullPath).catch((e) => {
68
+ if (e.code !== "ENOENT") {
69
+ throw e;
70
+ }
71
+ });
72
+ }
73
+ rolledBack++;
74
+ } catch (e) {
51
75
  conflicts.push({
52
76
  filePath: change.filePath,
53
77
  changeId: change.id,
54
- reason: `File was modified after this change by: ${laterAgents}. Use skipConflicts: true to force.`
78
+ reason: `Write failed: ${e instanceof Error ? e.message : String(e)}`
55
79
  });
56
80
  skipped++;
57
- continue;
58
- }
59
- }
60
- const fullPath = path.join(workingDir, change.filePath);
61
- try {
62
- if (change.before) {
63
- await promises.mkdir(path.dirname(fullPath), { recursive: true });
64
- await promises.writeFile(fullPath, change.before.content, "utf-8");
65
- } else {
66
- await promises.unlink(fullPath).catch((e) => {
67
- if (e.code !== "ENOENT") {
68
- throw e;
69
- }
70
- });
71
81
  }
72
- rolledBack++;
73
- } catch (e) {
74
- conflicts.push({
75
- filePath: change.filePath,
76
- changeId: change.id,
77
- reason: `Write failed: ${e instanceof Error ? e.message : String(e)}`
78
- });
79
- skipped++;
80
82
  }
83
+ ctx.platform.logger.info(
84
+ `[rollback-handler] Session ${sessionId}: rolled back ${rolledBack}, skipped ${skipped}`
85
+ );
86
+ return { rolledBack, skipped, conflicts, success: skipped === 0 };
87
+ } catch (err) {
88
+ rethrowForRest(err);
81
89
  }
82
- ctx.platform.logger.info(
83
- `[rollback-handler] Session ${sessionId}: rolled back ${rolledBack}, skipped ${skipped}`
84
- );
85
- return { rolledBack, skipped, conflicts, success: skipped === 0 };
86
90
  }
87
91
  });
88
92
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/rest/handlers/rollback-handler.ts"],"names":["fsp"],"mappings":"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","file":"rollback-handler.js","sourcesContent":["/**\n * POST /sessions/:sessionId/rollback — Rollback file changes.\n * Body: { runId?: string; changeIds?: string[]; skipConflicts?: boolean }\n */\n\nimport { defineHandler, type RestInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { SessionManager } from '@kb-labs/agent-core';\nimport { ChangeStore } from '@kb-labs/agent-history';\nimport type { FileChange } from '@kb-labs/agent-history';\nimport { promises as fsp } from 'node:fs';\nimport path from 'node:path';\n\ninterface RollbackRequest {\n runId?: string;\n changeIds?: string[];\n skipConflicts?: boolean;\n}\n\ninterface ConflictEntry {\n filePath: string;\n changeId: string;\n reason: string;\n}\n\ninterface RollbackResponse {\n rolledBack: number;\n skipped: number;\n conflicts: ConflictEntry[];\n success: boolean;\n}\n\nexport default defineHandler({\n async execute(ctx: PluginContextV3, input: RestInput<RollbackRequest>): Promise<RollbackResponse> {\n const params = input.params as Record<string, string> | undefined;\n const sessionId = params?.sessionId;\n if (!sessionId) {throw new Error('Session ID is required');}\n\n const body = (input.body ?? {}) as RollbackRequest;\n\n const sessionManager = new SessionManager(ctx.cwd);\n const session = await sessionManager.loadSession(sessionId);\n if (!session) {throw new Error(`Session not found: ${sessionId}`);}\n\n const workingDir = session.workingDir || ctx.cwd;\n const store = new ChangeStore(workingDir);\n\n let changes: FileChange[];\n if (body.runId) {\n changes = await store.listRun(sessionId, body.runId);\n } else if (body.changeIds?.length) {\n const ids = new Set(body.changeIds);\n const all = await store.listSession(sessionId);\n changes = all.filter((c) => ids.has(c.id));\n } else {\n changes = await store.listSession(sessionId);\n }\n\n if (changes.length === 0) {\n return { rolledBack: 0, skipped: 0, conflicts: [], success: true };\n }\n\n // Reverse-chronological: undo latest first\n const sorted = [...changes].sort(\n (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(),\n );\n\n // For conflict detection: full session history\n const fullHistory = await store.listSession(sessionId);\n const rollbackIds = new Set(sorted.map((c) => c.id));\n\n const conflicts: ConflictEntry[] = [];\n let rolledBack = 0;\n let skipped = 0;\n\n for (const change of sorted) {\n // Conflict: newer changes to same file NOT in our rollback set\n if (!body.skipConflicts) {\n const laterChanges = fullHistory.filter(\n (c) =>\n c.filePath === change.filePath &&\n new Date(c.timestamp).getTime() > new Date(change.timestamp).getTime() &&\n !rollbackIds.has(c.id),\n );\n if (laterChanges.length > 0) {\n const laterAgents = [...new Set(laterChanges.map((c) => c.agentId))].join(', ');\n conflicts.push({\n filePath: change.filePath,\n changeId: change.id,\n reason: `File was modified after this change by: ${laterAgents}. Use skipConflicts: true to force.`,\n });\n skipped++;\n continue;\n }\n }\n\n const fullPath = path.join(workingDir, change.filePath);\n try {\n if (change.before) {\n await fsp.mkdir(path.dirname(fullPath), { recursive: true });\n await fsp.writeFile(fullPath, change.before.content, 'utf-8');\n } else {\n await fsp.unlink(fullPath).catch((e: NodeJS.ErrnoException) => {\n if (e.code !== 'ENOENT') {throw e;}\n });\n }\n rolledBack++;\n } catch (e) {\n conflicts.push({\n filePath: change.filePath,\n changeId: change.id,\n reason: `Write failed: ${e instanceof Error ? e.message : String(e)}`,\n });\n skipped++;\n }\n }\n\n ctx.platform.logger.info(\n `[rollback-handler] Session ${sessionId}: rolled back ${rolledBack}, skipped ${skipped}`,\n );\n\n return { rolledBack, skipped, conflicts, success: skipped === 0 };\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/rest/handlers/rollback-handler.ts"],"names":["fsp"],"mappings":"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","file":"rollback-handler.js","sourcesContent":["/**\n * POST /sessions/:sessionId/rollback — Rollback file changes.\n * Body: { runId?: string; changeIds?: string[]; skipConflicts?: boolean }\n */\n\nimport { defineHandler, rethrowForRest, type RestInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { SessionManager } from '@kb-labs/agent-core';\nimport { ChangeStore } from '@kb-labs/agent-history';\nimport type { FileChange } from '@kb-labs/agent-history';\nimport { promises as fsp } from 'node:fs';\nimport path from 'node:path';\n\ninterface RollbackRequest {\n runId?: string;\n changeIds?: string[];\n skipConflicts?: boolean;\n}\n\ninterface ConflictEntry {\n filePath: string;\n changeId: string;\n reason: string;\n}\n\ninterface RollbackResponse {\n rolledBack: number;\n skipped: number;\n conflicts: ConflictEntry[];\n success: boolean;\n}\n\nexport default defineHandler({\n async execute(ctx: PluginContextV3, input: RestInput<RollbackRequest>): Promise<RollbackResponse> {\n try {\n const params = input.params as Record<string, string> | undefined;\n const sessionId = params?.sessionId;\n if (!sessionId) {throw new Error('Session ID is required');}\n\n const body = (input.body ?? {}) as RollbackRequest;\n\n const sessionManager = new SessionManager(ctx.cwd);\n const session = await sessionManager.loadSession(sessionId);\n if (!session) {throw new Error(`Session not found: ${sessionId}`);}\n\n const workingDir = session.workingDir || ctx.cwd;\n const store = new ChangeStore(workingDir);\n\n let changes: FileChange[];\n if (body.runId) {\n changes = await store.listRun(sessionId, body.runId);\n } else if (body.changeIds?.length) {\n const ids = new Set(body.changeIds);\n const all = await store.listSession(sessionId);\n changes = all.filter((c) => ids.has(c.id));\n } else {\n changes = await store.listSession(sessionId);\n }\n\n if (changes.length === 0) {\n return { rolledBack: 0, skipped: 0, conflicts: [], success: true };\n }\n\n // Reverse-chronological: undo latest first\n const sorted = [...changes].sort(\n (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(),\n );\n\n // For conflict detection: full session history\n const fullHistory = await store.listSession(sessionId);\n const rollbackIds = new Set(sorted.map((c) => c.id));\n\n const conflicts: ConflictEntry[] = [];\n let rolledBack = 0;\n let skipped = 0;\n\n for (const change of sorted) {\n // Conflict: newer changes to same file NOT in our rollback set\n if (!body.skipConflicts) {\n const laterChanges = fullHistory.filter(\n (c) =>\n c.filePath === change.filePath &&\n new Date(c.timestamp).getTime() > new Date(change.timestamp).getTime() &&\n !rollbackIds.has(c.id),\n );\n if (laterChanges.length > 0) {\n const laterAgents = [...new Set(laterChanges.map((c) => c.agentId))].join(', ');\n conflicts.push({\n filePath: change.filePath,\n changeId: change.id,\n reason: `File was modified after this change by: ${laterAgents}. Use skipConflicts: true to force.`,\n });\n skipped++;\n continue;\n }\n }\n\n const fullPath = path.join(workingDir, change.filePath);\n try {\n if (change.before) {\n await fsp.mkdir(path.dirname(fullPath), { recursive: true });\n await fsp.writeFile(fullPath, change.before.content, 'utf-8');\n } else {\n await fsp.unlink(fullPath).catch((e: NodeJS.ErrnoException) => {\n if (e.code !== 'ENOENT') {throw e;}\n });\n }\n rolledBack++;\n } catch (e) {\n conflicts.push({\n filePath: change.filePath,\n changeId: change.id,\n reason: `Write failed: ${e instanceof Error ? e.message : String(e)}`,\n });\n skipped++;\n }\n }\n\n ctx.platform.logger.info(\n `[rollback-handler] Session ${sessionId}: rolled back ${rolledBack}, skipped ${skipped}`,\n );\n\n return { rolledBack, skipped, conflicts, success: skipped === 0 };\n } catch (err) {\n rethrowForRest(err);\n }\n },\n});\n"]}
@@ -1,4 +1,4 @@
1
- import { defineHandler, useAnalytics, useCache, useConfig, usePlatform } from '@kb-labs/sdk';
1
+ import { defineHandler, useAnalytics, useCache, useConfig, rethrowForRest, usePlatform } from '@kb-labs/sdk';
2
2
  import { bootstrapAgentSDK, SessionManager, createSessionMemoryBridge, createCoreToolPack } from '@kb-labs/agent-core';
3
3
  import { createDefaultResponseRequirementsSelector } from '@kb-labs/agent-runtime';
4
4
  import { IncrementalTraceWriter } from '@kb-labs/agent-tracing';
@@ -353,161 +353,165 @@ async function inferFollowUpWorkingDir(sessionManager, sessionId, baseWorkingDir
353
353
  }
354
354
  var run_handler_default = defineHandler({
355
355
  async execute(ctx, input) {
356
- const body = input.body;
357
- if (!body?.task) {
358
- throw new Error("Task is required");
359
- }
360
- const analytics = useAnalytics();
361
- const runId = RunManager.generateRunId();
362
- const startTime = Date.now();
363
- let sessionId = body.sessionId;
364
- let workingDir = body.workingDir || ctx.cwd;
365
- let sessionManager = new SessionManager(workingDir);
366
- if (!sessionId) {
367
- const session = await sessionManager.createSession({
368
- mode: "execute",
369
- task: body.task,
370
- agentId: body.agentId ?? "orchestrator"
371
- });
372
- sessionId = session.id;
373
- ctx.platform.logger.info(`[run-handler] Created new session ${sessionId}`);
374
- } else {
375
- const existingSession = await sessionManager.loadSession(sessionId);
376
- let resolvedSession = existingSession;
377
- if (!resolvedSession && pathExists(ctx.cwd)) {
378
- const fallbackManager = new SessionManager(ctx.cwd);
379
- const fallbackSession = await fallbackManager.loadSession(sessionId);
380
- if (fallbackSession) {
381
- sessionManager = fallbackManager;
382
- resolvedSession = fallbackSession;
383
- }
356
+ try {
357
+ const body = input.body;
358
+ if (!body?.task) {
359
+ throw new Error("Task is required");
384
360
  }
385
- if (!resolvedSession) {
386
- throw new Error(`Session not found: ${sessionId} (cwd=${ctx.cwd})`);
387
- }
388
- workingDir = body.workingDir || resolvedSession.workingDir || workingDir;
389
- if (!body.workingDir && isLikelyFollowUpScopeTask(body.task)) {
390
- const inferred = await inferFollowUpWorkingDir(sessionManager, sessionId, resolvedSession.workingDir || ctx.cwd);
391
- if (inferred && inferred !== workingDir) {
392
- ctx.platform.logger.info(`[run-handler] Follow-up scope inferred: ${workingDir} -> ${inferred}`);
393
- workingDir = inferred;
361
+ const analytics = useAnalytics();
362
+ const runId = RunManager.generateRunId();
363
+ const startTime = Date.now();
364
+ let sessionId = body.sessionId;
365
+ let workingDir = body.workingDir || ctx.cwd;
366
+ let sessionManager = new SessionManager(workingDir);
367
+ if (!sessionId) {
368
+ const session = await sessionManager.createSession({
369
+ mode: "execute",
370
+ task: body.task,
371
+ agentId: body.agentId ?? "orchestrator"
372
+ });
373
+ sessionId = session.id;
374
+ ctx.platform.logger.info(`[run-handler] Created new session ${sessionId}`);
375
+ } else {
376
+ const existingSession = await sessionManager.loadSession(sessionId);
377
+ let resolvedSession = existingSession;
378
+ if (!resolvedSession && pathExists(ctx.cwd)) {
379
+ const fallbackManager = new SessionManager(ctx.cwd);
380
+ const fallbackSession = await fallbackManager.loadSession(sessionId);
381
+ if (fallbackSession) {
382
+ sessionManager = fallbackManager;
383
+ resolvedSession = fallbackSession;
384
+ }
385
+ }
386
+ if (!resolvedSession) {
387
+ throw new Error(`Session not found: ${sessionId} (cwd=${ctx.cwd})`);
388
+ }
389
+ workingDir = body.workingDir || resolvedSession.workingDir || workingDir;
390
+ if (!body.workingDir && isLikelyFollowUpScopeTask(body.task)) {
391
+ const inferred = await inferFollowUpWorkingDir(sessionManager, sessionId, resolvedSession.workingDir || ctx.cwd);
392
+ if (inferred && inferred !== workingDir) {
393
+ ctx.platform.logger.info(`[run-handler] Follow-up scope inferred: ${workingDir} -> ${inferred}`);
394
+ workingDir = inferred;
395
+ }
394
396
  }
397
+ sessionManager = new SessionManager(workingDir);
398
+ ctx.platform.logger.info(`[run-handler] Continuing session ${sessionId} (workingDir=${workingDir})`);
395
399
  }
396
- sessionManager = new SessionManager(workingDir);
397
- ctx.platform.logger.info(`[run-handler] Continuing session ${sessionId} (workingDir=${workingDir})`);
398
- }
399
- ctx.platform.logger.info(`[run-handler] Starting run ${runId} for task: ${body.task}`);
400
- await sessionManager.createUserTurn(sessionId, body.task, runId);
401
- await analytics?.track(AGENT_ANALYTICS_EVENTS.RUN_STARTED, {
402
- runId,
403
- sessionId,
404
- taskLength: body.task.length,
405
- tier: body.tier ?? "medium",
406
- enableEscalation: body.enableEscalation ?? true,
407
- responseMode: body.responseMode ?? "auto",
408
- verbose: body.verbose ?? false
409
- });
410
- const sessionMemory = createSessionMemoryBridge(workingDir, sessionId);
411
- const responseRequirementsSelector = createDefaultResponseRequirementsSelector();
412
- const toolRegistry = createToolRegistry({
413
- workingDir,
414
- currentTask: body.task,
415
- sessionId,
416
- verbose: body.verbose,
417
- cache: useCache(),
418
- sessionMemory,
419
- responseRequirementsResolver: async ({ task, kernel }) => responseRequirementsSelector.select({
420
- state: kernel,
421
- messages: [],
422
- task: task ?? body.task
423
- })
424
- });
425
- const agentsConfig = await useConfig();
426
- const finalSessionId = sessionId;
427
- const traceDir = path.join(workingDir, ".kb", "traces", "incremental");
428
- const traceWriter = new IncrementalTraceWriter(runId, {}, traceDir);
429
- const agent = new AgentSDK().register(createCoreToolPack(toolRegistry)).createRunner({
430
- sessionId: finalSessionId,
431
- workingDir,
432
- maxIterations: 50,
433
- temperature: 0.1,
434
- tier: body.tier ?? "medium",
435
- tokenBudget: agentsConfig?.tokenBudget,
436
- onEvent: (event) => {
437
- const seqEvent = RunManager.broadcast(runId, event);
438
- void sessionManager.addEvent(finalSessionId, {
439
- ...seqEvent,
440
- sessionId: finalSessionId,
441
- runId,
442
- metadata: {
443
- ...seqEvent.metadata,
400
+ ctx.platform.logger.info(`[run-handler] Starting run ${runId} for task: ${body.task}`);
401
+ await sessionManager.createUserTurn(sessionId, body.task, runId);
402
+ await analytics?.track(AGENT_ANALYTICS_EVENTS.RUN_STARTED, {
403
+ runId,
404
+ sessionId,
405
+ taskLength: body.task.length,
406
+ tier: body.tier ?? "medium",
407
+ enableEscalation: body.enableEscalation ?? true,
408
+ responseMode: body.responseMode ?? "auto",
409
+ verbose: body.verbose ?? false
410
+ });
411
+ const sessionMemory = createSessionMemoryBridge(workingDir, sessionId);
412
+ const responseRequirementsSelector = createDefaultResponseRequirementsSelector();
413
+ const toolRegistry = createToolRegistry({
414
+ workingDir,
415
+ currentTask: body.task,
416
+ sessionId,
417
+ verbose: body.verbose,
418
+ cache: useCache(),
419
+ sessionMemory,
420
+ responseRequirementsResolver: async ({ task, kernel }) => responseRequirementsSelector.select({
421
+ state: kernel,
422
+ messages: [],
423
+ task: task ?? body.task
424
+ })
425
+ });
426
+ const agentsConfig = await useConfig();
427
+ const finalSessionId = sessionId;
428
+ const traceDir = path.join(workingDir, ".kb", "traces", "incremental");
429
+ const traceWriter = new IncrementalTraceWriter(runId, {}, traceDir);
430
+ const agent = new AgentSDK().register(createCoreToolPack(toolRegistry)).createRunner({
431
+ sessionId: finalSessionId,
432
+ workingDir,
433
+ maxIterations: 50,
434
+ temperature: 0.1,
435
+ tier: body.tier ?? "medium",
436
+ tokenBudget: agentsConfig?.tokenBudget,
437
+ onEvent: (event) => {
438
+ const seqEvent = RunManager.broadcast(runId, event);
439
+ void sessionManager.addEvent(finalSessionId, {
440
+ ...seqEvent,
444
441
  sessionId: finalSessionId,
445
442
  runId,
446
- workingDir
447
- }
448
- });
449
- }
450
- });
451
- const run = await RunManager.register(runId, body.task, agent, sessionManager, finalSessionId);
452
- await RunManager.updateStatus(runId, "running");
453
- void (async () => {
454
- try {
455
- const result = await agent.execute(body.task);
456
- const durationMs = Date.now() - startTime;
457
- const detailedTrace = traceWriter.getEntries();
458
- await traceWriter.finalize?.();
459
- if (detailedTrace.length > 0) {
460
- await sessionManager.storeTraceArtifacts(finalSessionId, runId, detailedTrace);
461
- }
462
- if (result.fileChanges && result.fileChanges.length > 0) {
463
- await sessionManager.attachFileChangesToTurn(finalSessionId, runId, result.fileChanges);
443
+ metadata: {
444
+ ...seqEvent.metadata,
445
+ sessionId: finalSessionId,
446
+ runId,
447
+ workingDir
448
+ }
449
+ });
464
450
  }
465
- await RunManager.updateStatus(runId, result.success ? "completed" : "failed", {
466
- completedAt: (/* @__PURE__ */ new Date()).toISOString(),
467
- durationMs,
468
- summary: result.summary,
469
- error: result.error
470
- });
471
- await analytics?.track(
472
- result.success ? AGENT_ANALYTICS_EVENTS.RUN_COMPLETED : AGENT_ANALYTICS_EVENTS.RUN_FAILED,
473
- {
474
- runId,
451
+ });
452
+ const run = await RunManager.register(runId, body.task, agent, sessionManager, finalSessionId);
453
+ await RunManager.updateStatus(runId, "running");
454
+ void (async () => {
455
+ try {
456
+ const result = await agent.execute(body.task);
457
+ const durationMs = Date.now() - startTime;
458
+ const detailedTrace = traceWriter.getEntries();
459
+ await traceWriter.finalize?.();
460
+ if (detailedTrace.length > 0) {
461
+ await sessionManager.storeTraceArtifacts(finalSessionId, runId, detailedTrace);
462
+ }
463
+ if (result.fileChanges && result.fileChanges.length > 0) {
464
+ await sessionManager.attachFileChangesToTurn(finalSessionId, runId, result.fileChanges);
465
+ }
466
+ await RunManager.updateStatus(runId, result.success ? "completed" : "failed", {
467
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
475
468
  durationMs,
476
- success: result.success,
477
- summary: result.summary?.slice(0, 200)
469
+ summary: result.summary,
470
+ error: result.error
471
+ });
472
+ await analytics?.track(
473
+ result.success ? AGENT_ANALYTICS_EVENTS.RUN_COMPLETED : AGENT_ANALYTICS_EVENTS.RUN_FAILED,
474
+ {
475
+ runId,
476
+ durationMs,
477
+ success: result.success,
478
+ summary: result.summary?.slice(0, 200)
479
+ }
480
+ );
481
+ ctx.platform.logger.info(`[run-handler] Run ${runId} completed: ${result.success}`);
482
+ } catch (error) {
483
+ const errorMsg = error instanceof Error ? error.message : String(error);
484
+ const durationMs = Date.now() - startTime;
485
+ const detailedTrace = traceWriter.getEntries();
486
+ await traceWriter.finalize?.();
487
+ if (detailedTrace.length > 0) {
488
+ await sessionManager.storeTraceArtifacts(finalSessionId, runId, detailedTrace);
478
489
  }
479
- );
480
- ctx.platform.logger.info(`[run-handler] Run ${runId} completed: ${result.success}`);
481
- } catch (error) {
482
- const errorMsg = error instanceof Error ? error.message : String(error);
483
- const durationMs = Date.now() - startTime;
484
- const detailedTrace = traceWriter.getEntries();
485
- await traceWriter.finalize?.();
486
- if (detailedTrace.length > 0) {
487
- await sessionManager.storeTraceArtifacts(finalSessionId, runId, detailedTrace);
490
+ await RunManager.updateStatus(runId, "failed", {
491
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
492
+ durationMs,
493
+ error: errorMsg
494
+ });
495
+ await analytics?.track(AGENT_ANALYTICS_EVENTS.RUN_FAILED, {
496
+ runId,
497
+ durationMs,
498
+ error: errorMsg.slice(0, 200)
499
+ });
500
+ ctx.platform.logger.error(`[run-handler] Run ${runId} failed: ${errorMsg}`);
488
501
  }
489
- await RunManager.updateStatus(runId, "failed", {
490
- completedAt: (/* @__PURE__ */ new Date()).toISOString(),
491
- durationMs,
492
- error: errorMsg
493
- });
494
- await analytics?.track(AGENT_ANALYTICS_EVENTS.RUN_FAILED, {
495
- runId,
496
- durationMs,
497
- error: errorMsg.slice(0, 200)
498
- });
499
- ctx.platform.logger.error(`[run-handler] Run ${runId} failed: ${errorMsg}`);
500
- }
501
- })();
502
- const wsPath = AGENTS_WS_CHANNELS.SESSION_STREAM.replace(":sessionId", finalSessionId);
503
- const eventsPath = `${AGENTS_WS_BASE_PATH}${wsPath}`;
504
- return {
505
- runId,
506
- sessionId: finalSessionId,
507
- eventsPath,
508
- status: "started",
509
- startedAt: run.startedAt
510
- };
502
+ })();
503
+ const wsPath = AGENTS_WS_CHANNELS.SESSION_STREAM.replace(":sessionId", finalSessionId);
504
+ const eventsPath = `${AGENTS_WS_BASE_PATH}${wsPath}`;
505
+ return {
506
+ runId,
507
+ sessionId: finalSessionId,
508
+ eventsPath,
509
+ status: "started",
510
+ startedAt: run.startedAt
511
+ };
512
+ } catch (err) {
513
+ rethrowForRest(err);
514
+ }
511
515
  }
512
516
  });
513
517