@kernel.chat/kbot 2.27.0 → 3.0.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/agent.d.ts +15 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +187 -48
- package/dist/agent.js.map +1 -1
- package/dist/checkpoint.d.ts +79 -0
- package/dist/checkpoint.d.ts.map +1 -0
- package/dist/checkpoint.js +220 -0
- package/dist/checkpoint.js.map +1 -0
- package/dist/cli.js +55 -4
- package/dist/cli.js.map +1 -1
- package/dist/ide/bridge.d.ts +2 -0
- package/dist/ide/bridge.d.ts.map +1 -1
- package/dist/ide/bridge.js +1 -0
- package/dist/ide/bridge.js.map +1 -1
- package/dist/ide/mcp-server.d.ts.map +1 -1
- package/dist/ide/mcp-server.js +27 -7
- package/dist/ide/mcp-server.js.map +1 -1
- package/dist/learned-router.d.ts +9 -7
- package/dist/learned-router.d.ts.map +1 -1
- package/dist/learned-router.js +36 -10
- package/dist/learned-router.js.map +1 -1
- package/dist/learning.d.ts +4 -0
- package/dist/learning.d.ts.map +1 -1
- package/dist/learning.js +17 -0
- package/dist/learning.js.map +1 -1
- package/dist/multimodal.d.ts +6 -0
- package/dist/multimodal.d.ts.map +1 -1
- package/dist/multimodal.js +45 -0
- package/dist/multimodal.js.map +1 -1
- package/dist/sdk.d.ts +165 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +230 -0
- package/dist/sdk.js.map +1 -0
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +38 -0
- package/dist/serve.js.map +1 -1
- package/dist/skill-rating.d.ts +92 -0
- package/dist/skill-rating.d.ts.map +1 -0
- package/dist/skill-rating.js +352 -0
- package/dist/skill-rating.js.map +1 -0
- package/dist/streaming.d.ts +75 -1
- package/dist/streaming.d.ts.map +1 -1
- package/dist/streaming.js +211 -3
- package/dist/streaming.js.map +1 -1
- package/dist/task-ledger.d.ts +10 -0
- package/dist/task-ledger.d.ts.map +1 -1
- package/dist/task-ledger.js +28 -0
- package/dist/task-ledger.js.map +1 -1
- package/dist/telemetry.d.ts +52 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +219 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/terminal-caps.d.ts +20 -0
- package/dist/terminal-caps.d.ts.map +1 -0
- package/dist/terminal-caps.js +80 -0
- package/dist/terminal-caps.js.map +1 -0
- package/dist/tool-pipeline.d.ts +86 -0
- package/dist/tool-pipeline.d.ts.map +1 -0
- package/dist/tool-pipeline.js +200 -0
- package/dist/tool-pipeline.js.map +1 -0
- package/dist/tools/index.d.ts +45 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +168 -108
- package/dist/tools/index.js.map +1 -1
- package/dist/tui.d.ts +1 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +71 -11
- package/dist/tui.js.map +1 -1
- package/dist/ui-adapter.d.ts +73 -0
- package/dist/ui-adapter.d.ts.map +1 -0
- package/dist/ui-adapter.js +139 -0
- package/dist/ui-adapter.js.map +1 -0
- package/dist/ui.d.ts +3 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +21 -2
- package/dist/ui.js.map +1 -1
- package/package.json +22 -3
package/dist/agent.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { ToolPipeline } from './tool-pipeline.js';
|
|
1
2
|
import { type ProjectContext } from './context.js';
|
|
3
|
+
import type { UIAdapter } from './ui-adapter.js';
|
|
2
4
|
import { type ParsedMessage } from './multimodal.js';
|
|
5
|
+
import { ResponseStream } from './streaming.js';
|
|
6
|
+
import { type Checkpoint } from './checkpoint.js';
|
|
3
7
|
export interface AgentOptions {
|
|
4
8
|
agent?: string;
|
|
5
9
|
model?: string;
|
|
@@ -14,6 +18,12 @@ export interface AgentOptions {
|
|
|
14
18
|
multimodal?: ParsedMessage;
|
|
15
19
|
/** Skip planner re-entry (prevents infinite loop when planner calls runAgent) */
|
|
16
20
|
skipPlanner?: boolean;
|
|
21
|
+
/** UIAdapter for decoupled output (SDK use). Defaults to TerminalUIAdapter. */
|
|
22
|
+
ui?: UIAdapter;
|
|
23
|
+
/** Custom tool execution pipeline (overrides default permission/hook/metrics chain) */
|
|
24
|
+
pipeline?: ToolPipeline;
|
|
25
|
+
/** ResponseStream for structured event streaming (SDK/MCP/HTTP consumers) */
|
|
26
|
+
responseStream?: ResponseStream;
|
|
17
27
|
}
|
|
18
28
|
export interface AgentResponse {
|
|
19
29
|
content: string;
|
|
@@ -31,4 +41,9 @@ export interface AgentResponse {
|
|
|
31
41
|
export declare function runAgent(message: string, options?: AgentOptions): Promise<AgentResponse>;
|
|
32
42
|
/** One-shot: run agent and print response */
|
|
33
43
|
export declare function runAndPrint(message: string, options?: AgentOptions): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Resume an agent session from a checkpoint.
|
|
46
|
+
* Restores conversation messages and state, then continues execution.
|
|
47
|
+
*/
|
|
48
|
+
export declare function runAgentFromCheckpoint(checkpoint: Checkpoint, options?: AgentOptions): Promise<AgentResponse>;
|
|
34
49
|
//# sourceMappingURL=agent.d.ts.map
|
package/dist/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAyBA,OAAO,EACL,YAAY,EAGb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAA0B,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAc1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAA8E,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAChI,OAAO,EAAiD,cAAc,EAAoB,MAAM,gBAAgB,CAAA;AAShH,OAAO,EAAmC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAA;AA0DlF,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,cAAc,CAAA;IACxB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uDAAuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,sDAAsD;IACtD,UAAU,CAAC,EAAE,aAAa,CAAA;IAC1B,iFAAiF;IACjF,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,+EAA+E;IAC/E,EAAE,CAAC,EAAE,SAAS,CAAA;IACd,uFAAuF;IACvF,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,cAAc,CAAA;CAChC;AAGD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAC1E;AAsqBD,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,aAAa,CAAC,CAyoBxB;AAGD,6CAA6C;AAC7C,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAkEf;AAGD;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,aAAa,CAAC,CAgCxB"}
|
package/dist/agent.js
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
// 6. Verify: always confirm the output exists and is correct
|
|
11
11
|
// 7. Learn: extract knowledge from every interaction for future use
|
|
12
12
|
import { getByokKey, getByokProvider, getProviderModel, getProvider, estimateCost, isLocalProvider, warmOllamaModelCache, } from './auth.js';
|
|
13
|
-
import { executeTool, getTool, getToolDefinitionsForApi, } from './tools/index.js';
|
|
13
|
+
import { executeTool, getTool, getToolDefinitionsForApi, ensureLazyToolsLoaded, } from './tools/index.js';
|
|
14
|
+
import { createDefaultPipeline, } from './tool-pipeline.js';
|
|
14
15
|
import { formatContextForPrompt } from './context.js';
|
|
15
16
|
import { getMatrixSystemPrompt } from './matrix.js';
|
|
16
17
|
import { buildFullLearningContext, findPattern, recordPattern, cacheSolution, updateProfile, classifyTask, extractKeywords, learnFromExchange, updateProjectMemory, shouldAutoTrain, selfTrain, } from './learning.js';
|
|
@@ -19,7 +20,8 @@ import { autoCompact, compressToolResult } from './context-manager.js';
|
|
|
19
20
|
import { learnedRoute, recordRoute } from './learned-router.js';
|
|
20
21
|
import { buildCacheablePrompt, createPromptSections } from './prompt-cache.js';
|
|
21
22
|
import { saveEmbeddingCache } from './embeddings.js';
|
|
22
|
-
import {
|
|
23
|
+
import { printResponse, printError, printInfo, printWarn } from './ui.js';
|
|
24
|
+
import { TerminalUIAdapter } from './ui-adapter.js';
|
|
23
25
|
import { parseMultimodalMessage, toAnthropicContent } from './multimodal.js';
|
|
24
26
|
import { streamAnthropicResponse, streamOpenAIResponse } from './streaming.js';
|
|
25
27
|
import { checkPermission } from './permissions.js';
|
|
@@ -29,6 +31,8 @@ import { recordSuccess, recordFailure } from './provider-fallback.js';
|
|
|
29
31
|
import { isSelfEvalEnabled, evaluateResponse } from './self-eval.js';
|
|
30
32
|
import { EntropyScorer } from './entropy-context.js';
|
|
31
33
|
import { LoopDetector } from './godel-limits.js';
|
|
34
|
+
import { CheckpointManager, newSessionId } from './checkpoint.js';
|
|
35
|
+
import { TelemetryEmitter } from './telemetry.js';
|
|
32
36
|
const MAX_TOOL_LOOPS = 75;
|
|
33
37
|
/** Maximum cumulative cost (USD) before auto-stopping tool loops */
|
|
34
38
|
const MAX_COST_CEILING = 1.00;
|
|
@@ -488,10 +492,10 @@ async function callProviderStreaming(provider, apiKey, model, systemContext, mes
|
|
|
488
492
|
const p = getProvider(provider);
|
|
489
493
|
let state;
|
|
490
494
|
if (p.apiStyle === 'anthropic') {
|
|
491
|
-
state = await streamAnthropicResponse(apiKey, p.apiUrl, model, systemContext, messages.map(m => ({ role: m.role, content: m.content })), tools, { thinking: options?.thinking, thinkingBudget: options?.thinkingBudget });
|
|
495
|
+
state = await streamAnthropicResponse(apiKey, p.apiUrl, model, systemContext, messages.map(m => ({ role: m.role, content: m.content })), tools, { thinking: options?.thinking, thinkingBudget: options?.thinkingBudget, responseStream: options?.responseStream });
|
|
492
496
|
}
|
|
493
497
|
else {
|
|
494
|
-
state = await streamOpenAIResponse(apiKey, p.apiUrl, model, systemContext, messages.map(m => ({ role: m.role, content: m.content })), tools);
|
|
498
|
+
state = await streamOpenAIResponse(apiKey, p.apiUrl, model, systemContext, messages.map(m => ({ role: m.role, content: m.content })), tools, { responseStream: options?.responseStream });
|
|
495
499
|
}
|
|
496
500
|
const result = {
|
|
497
501
|
content: state.content,
|
|
@@ -653,6 +657,8 @@ async function callProvider(provider, apiKey, model, systemContext, messages, to
|
|
|
653
657
|
}
|
|
654
658
|
// ── Main agent loop ──
|
|
655
659
|
export async function runAgent(message, options = {}) {
|
|
660
|
+
// UIAdapter: defaults to TerminalUIAdapter for CLI, can be overridden for SDK use
|
|
661
|
+
const ui = options.ui ?? new TerminalUIAdapter();
|
|
656
662
|
const apiKey = getByokKey();
|
|
657
663
|
const byokProvider = getByokProvider();
|
|
658
664
|
const isLocal = byokProvider ? isLocalProvider(byokProvider) : false;
|
|
@@ -666,7 +672,7 @@ export async function runAgent(message, options = {}) {
|
|
|
666
672
|
// Step 0: Parse multimodal content (images in message)
|
|
667
673
|
const parsed = options.multimodal || parseMultimodalMessage(message);
|
|
668
674
|
if (parsed.isMultimodal) {
|
|
669
|
-
|
|
675
|
+
ui.onInfo(`(${parsed.imageCount} image${parsed.imageCount > 1 ? 's' : ''} attached)`);
|
|
670
676
|
}
|
|
671
677
|
// Step 1: Local-first (skip if multimodal — needs AI to interpret)
|
|
672
678
|
if (!parsed.isMultimodal) {
|
|
@@ -674,13 +680,13 @@ export async function runAgent(message, options = {}) {
|
|
|
674
680
|
if (localResult !== null) {
|
|
675
681
|
addTurn({ role: 'user', content: message });
|
|
676
682
|
addTurn({ role: 'assistant', content: localResult });
|
|
677
|
-
|
|
683
|
+
ui.onInfo('(handled locally — 0 tokens used)');
|
|
678
684
|
return { content: localResult, agent: 'local', model: 'none', toolCalls: 0 };
|
|
679
685
|
}
|
|
680
686
|
}
|
|
681
687
|
// Step 1.5: Complexity detection — auto-plan complex tasks
|
|
682
688
|
if (isComplexTask(message) && !message.startsWith('/plan') && !options.skipPlanner) {
|
|
683
|
-
|
|
689
|
+
ui.onInfo('Complex task detected. Using autonomous planner...');
|
|
684
690
|
try {
|
|
685
691
|
const { autonomousExecute, formatPlanSummary } = await import('./planner.js');
|
|
686
692
|
const plan = await autonomousExecute(message, {
|
|
@@ -699,7 +705,7 @@ export async function runAgent(message, options = {}) {
|
|
|
699
705
|
}
|
|
700
706
|
catch {
|
|
701
707
|
// Planner failed — fall through to regular agent loop
|
|
702
|
-
|
|
708
|
+
ui.onWarning('Planner failed, falling back to direct execution...');
|
|
703
709
|
}
|
|
704
710
|
}
|
|
705
711
|
// Step 1.7: Learned routing — try cached route before defaulting
|
|
@@ -710,6 +716,9 @@ export async function runAgent(message, options = {}) {
|
|
|
710
716
|
}
|
|
711
717
|
}
|
|
712
718
|
const tier = options.tier || 'free';
|
|
719
|
+
// Ensure lazy tools are loaded before building the tool list for the API.
|
|
720
|
+
// In one-shot mode, lazy tools may still be loading in background — await them here.
|
|
721
|
+
await ensureLazyToolsLoaded();
|
|
713
722
|
const allTools = getToolDefinitionsForApi(tier);
|
|
714
723
|
const casual = isCasualMessage(message);
|
|
715
724
|
// Smart tool filtering:
|
|
@@ -830,6 +839,15 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
830
839
|
const toolSequenceLog = [];
|
|
831
840
|
const originalMessage = message;
|
|
832
841
|
let cumulativeCostUsd = 0;
|
|
842
|
+
// ── Checkpointing & Telemetry ──
|
|
843
|
+
const sessionId = newSessionId();
|
|
844
|
+
const checkpointManager = new CheckpointManager();
|
|
845
|
+
const telemetry = new TelemetryEmitter(sessionId);
|
|
846
|
+
telemetry.emit('session_start', {
|
|
847
|
+
agent: options.agent || 'kernel',
|
|
848
|
+
model: options.model || 'auto',
|
|
849
|
+
message: originalMessage.slice(0, 200),
|
|
850
|
+
});
|
|
833
851
|
// ── Gödel limits: detect undecidable loops and hand off to human ──
|
|
834
852
|
const loopDetector = new LoopDetector({
|
|
835
853
|
maxToolRepeats: 5,
|
|
@@ -839,6 +857,23 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
839
857
|
});
|
|
840
858
|
// ── Entropy scorer: information-theoretic context management ──
|
|
841
859
|
const entropyScorer = new EntropyScorer();
|
|
860
|
+
// ── Tool execution pipeline ──
|
|
861
|
+
const pipeline = options.pipeline ?? createDefaultPipeline({
|
|
862
|
+
checkPermission,
|
|
863
|
+
runPreHook: (name, args) => {
|
|
864
|
+
const h = runPreToolHook(name, args, options.agent || 'kernel');
|
|
865
|
+
return { blocked: h.blocked ?? false, blockReason: h.blockReason };
|
|
866
|
+
},
|
|
867
|
+
runPostHook: (name, args, result) => { runPostToolHook(name, args, result, options.agent || 'kernel'); },
|
|
868
|
+
executeTool: async (name, args) => {
|
|
869
|
+
const r = await executeTool({ id: name, name, arguments: args });
|
|
870
|
+
return { result: r.result, error: r.error ? r.result : undefined };
|
|
871
|
+
},
|
|
872
|
+
recordMetrics: (name, duration, error) => {
|
|
873
|
+
telemetry.emit('tool_call_end', { tool: name, duration_ms: duration, error });
|
|
874
|
+
},
|
|
875
|
+
emit: (event, data) => telemetry.emit(event, data),
|
|
876
|
+
});
|
|
842
877
|
// Loop messages track the full conversation within a multi-tool execution.
|
|
843
878
|
// This includes assistant responses (with tool-use reasoning) and tool results,
|
|
844
879
|
// so the AI maintains context across tool iterations.
|
|
@@ -846,7 +881,7 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
846
881
|
for (let i = 0; i < MAX_TOOL_LOOPS; i++) {
|
|
847
882
|
// Cost ceiling — stop burning money on runaway loops
|
|
848
883
|
if (cumulativeCostUsd > MAX_COST_CEILING) {
|
|
849
|
-
|
|
884
|
+
ui.onWarning(`Cost ceiling reached ($${cumulativeCostUsd.toFixed(2)} > $${MAX_COST_CEILING}). Stopping tool loop.`);
|
|
850
885
|
break;
|
|
851
886
|
}
|
|
852
887
|
// ── Gödel check: detect stuck loops before burning more tokens ──
|
|
@@ -857,23 +892,22 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
857
892
|
? `Loop detected (${decidability.pattern}): ${decidability.evidence}`
|
|
858
893
|
: decidability.evidence;
|
|
859
894
|
if (decidability.recommendation === 'handoff') {
|
|
860
|
-
|
|
895
|
+
ui.onWarning(`${msg}\nHanding off to you — I need your input to continue.`);
|
|
861
896
|
break;
|
|
862
897
|
}
|
|
863
898
|
else if (decidability.recommendation === 'decompose') {
|
|
864
|
-
|
|
899
|
+
ui.onWarning(`${msg}\nBreaking this into smaller steps...`);
|
|
865
900
|
break;
|
|
866
901
|
}
|
|
867
902
|
else if (decidability.recommendation === 'simplify') {
|
|
868
|
-
|
|
903
|
+
ui.onInfo(`${msg} Trying a different approach...`);
|
|
869
904
|
loopMessages.push({ role: 'user', content: `Your approach isn't working. Try a completely different strategy. ${decidability.evidence}` });
|
|
870
905
|
}
|
|
871
906
|
}
|
|
872
907
|
}
|
|
873
908
|
// Don't use spinner when streaming (conflicts with stdout)
|
|
874
909
|
const useSpinner = !options.stream;
|
|
875
|
-
const
|
|
876
|
-
spinner?.start();
|
|
910
|
+
const spinnerHandle = useSpinner ? ui.onSpinnerStart(i === 0 ? 'Thinking...' : `Running tools (${toolCallCount})...`) : null;
|
|
877
911
|
try {
|
|
878
912
|
// ── BYOK: Call provider directly with tool-use support ──
|
|
879
913
|
// If user passed an explicit model name (not a speed alias), use it directly
|
|
@@ -911,7 +945,7 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
911
945
|
role: t.role,
|
|
912
946
|
content: t.content,
|
|
913
947
|
}));
|
|
914
|
-
|
|
948
|
+
spinnerHandle?.stop();
|
|
915
949
|
// Use streaming if requested and provider supports it
|
|
916
950
|
// Disable streaming for local models when tools are active — local models
|
|
917
951
|
// often emit tool calls as raw JSON text, which can't be cleaned up after streaming
|
|
@@ -920,18 +954,39 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
920
954
|
&& p.apiStyle !== 'google'
|
|
921
955
|
&& p.apiStyle !== 'cohere'
|
|
922
956
|
&& !(isLocal && byokTools.length > 0); // Don't stream local + tools (inline tool parsing needs full response)
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
957
|
+
// ── Telemetry: API call ──
|
|
958
|
+
const apiCallStartMs = Date.now();
|
|
959
|
+
telemetry.emit('api_call', { provider, model, iteration: i, streaming: !!canStream });
|
|
960
|
+
let result;
|
|
961
|
+
try {
|
|
962
|
+
result = canStream
|
|
963
|
+
? await callProviderStreaming(provider, apiKey || 'local', model, systemContext, messages, byokTools, {
|
|
964
|
+
thinking: options.thinking,
|
|
965
|
+
thinkingBudget: options.thinkingBudget,
|
|
966
|
+
responseStream: options.responseStream,
|
|
967
|
+
})
|
|
968
|
+
: await callProvider(provider, apiKey || 'local', model, systemContext, messages, byokTools, {
|
|
969
|
+
multimodal: i === 0 ? parsed : undefined,
|
|
970
|
+
thinking: options.thinking,
|
|
971
|
+
thinkingBudget: options.thinkingBudget,
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
catch (apiErr) {
|
|
975
|
+
telemetry.emit('api_error', {
|
|
976
|
+
provider, model, iteration: i,
|
|
977
|
+
error: apiErr instanceof Error ? apiErr.message : String(apiErr),
|
|
978
|
+
}, Date.now() - apiCallStartMs);
|
|
979
|
+
throw apiErr;
|
|
980
|
+
}
|
|
933
981
|
const iterationCost = estimateCost(provider, result.usage.input_tokens, result.usage.output_tokens);
|
|
934
982
|
cumulativeCostUsd += iterationCost;
|
|
983
|
+
telemetry.emit('cost_update', {
|
|
984
|
+
iteration: i,
|
|
985
|
+
iterationCost,
|
|
986
|
+
cumulativeCostUsd,
|
|
987
|
+
inputTokens: result.usage.input_tokens,
|
|
988
|
+
outputTokens: result.usage.output_tokens,
|
|
989
|
+
}, Date.now() - apiCallStartMs);
|
|
935
990
|
// ── Feed Gödel detector with cost/token data ──
|
|
936
991
|
loopDetector.recordCost(iterationCost);
|
|
937
992
|
loopDetector.recordTokens(result.usage.input_tokens + result.usage.output_tokens);
|
|
@@ -980,7 +1035,7 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
980
1035
|
if (classification && classification.confidence > 0.7) {
|
|
981
1036
|
const { applyCorrection } = await import('./error-correction.js');
|
|
982
1037
|
const correctionPrompt = applyCorrection(originalMessage, content, classification.errorType, classification.evidence);
|
|
983
|
-
|
|
1038
|
+
ui.onWarning(`Error correction: ${classification.errorType} (${(classification.confidence * 100).toFixed(0)}%) — retrying with fix...`);
|
|
984
1039
|
loopMessages.push({ role: 'assistant', content });
|
|
985
1040
|
loopMessages.push({ role: 'user', content: correctionPrompt });
|
|
986
1041
|
continue;
|
|
@@ -993,7 +1048,7 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
993
1048
|
try {
|
|
994
1049
|
const evalResult = await evaluateResponse(originalMessage, content);
|
|
995
1050
|
if (evalResult.shouldRetry && evalResult.feedback) {
|
|
996
|
-
|
|
1051
|
+
ui.onWarning(`Self-eval: low score (${evalResult.overall.toFixed(2)}), retrying...`);
|
|
997
1052
|
loopMessages.push({ role: 'assistant', content });
|
|
998
1053
|
loopMessages.push({ role: 'user', content: `Your previous response scored low on quality. Feedback: ${evalResult.feedback}\n\nPlease try again with a better response.` });
|
|
999
1054
|
continue;
|
|
@@ -1020,13 +1075,15 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
1020
1075
|
if (content.length > 50 && toolCallCount <= 5) {
|
|
1021
1076
|
cacheSolution(originalMessage, content.slice(0, 2000));
|
|
1022
1077
|
}
|
|
1023
|
-
// Update user profile
|
|
1078
|
+
// Update user profile + Bayesian skill ratings
|
|
1024
1079
|
updateProfile({
|
|
1025
1080
|
tokens: totalTokens,
|
|
1026
1081
|
tokensSaved: findPattern(originalMessage)?.avgTokensSaved || 0,
|
|
1027
1082
|
agent: lastResponse.agent || 'kernel',
|
|
1028
1083
|
taskType: classifyTask(originalMessage),
|
|
1029
1084
|
techTerms: extractKeywords(originalMessage),
|
|
1085
|
+
message: originalMessage,
|
|
1086
|
+
success: true,
|
|
1030
1087
|
});
|
|
1031
1088
|
// Record routing decision for learned router
|
|
1032
1089
|
const routeMethod = learnedRoute(originalMessage)?.method || 'llm';
|
|
@@ -1076,6 +1133,14 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
1076
1133
|
}
|
|
1077
1134
|
catch { /* learning failures are non-critical */ }
|
|
1078
1135
|
});
|
|
1136
|
+
// ── Checkpoint & Telemetry: session completed successfully ──
|
|
1137
|
+
checkpointManager.markCompleted(sessionId).catch(() => { });
|
|
1138
|
+
telemetry.emit('session_end', {
|
|
1139
|
+
status: 'completed',
|
|
1140
|
+
toolCallCount,
|
|
1141
|
+
cumulativeCostUsd,
|
|
1142
|
+
});
|
|
1143
|
+
telemetry.destroy().catch(() => { });
|
|
1079
1144
|
return {
|
|
1080
1145
|
content,
|
|
1081
1146
|
agent: lastResponse.agent || 'kernel',
|
|
@@ -1091,28 +1156,39 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
1091
1156
|
for (const call of toolCalls) {
|
|
1092
1157
|
toolCallCount++;
|
|
1093
1158
|
toolSequenceLog.push(call.name);
|
|
1094
|
-
|
|
1095
|
-
//
|
|
1096
|
-
const
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1159
|
+
ui.onToolCallStart(call.name, call.arguments || {});
|
|
1160
|
+
// Execute through the middleware pipeline
|
|
1161
|
+
const ctx = {
|
|
1162
|
+
toolName: call.name,
|
|
1163
|
+
toolArgs: call.arguments || {},
|
|
1164
|
+
toolCallId: call.id,
|
|
1165
|
+
metadata: {},
|
|
1166
|
+
aborted: false,
|
|
1167
|
+
};
|
|
1168
|
+
await pipeline.execute(ctx);
|
|
1169
|
+
// Build ToolResult from pipeline context
|
|
1170
|
+
const result = {
|
|
1171
|
+
tool_call_id: call.id,
|
|
1172
|
+
result: ctx.error
|
|
1173
|
+
? (ctx.aborted ? (ctx.abortReason || ctx.error) : `Tool error: ${ctx.error}`)
|
|
1174
|
+
: (ctx.result || ''),
|
|
1175
|
+
error: !!ctx.error || ctx.aborted,
|
|
1176
|
+
duration_ms: ctx.durationMs,
|
|
1177
|
+
};
|
|
1110
1178
|
results.push(result);
|
|
1111
|
-
|
|
1179
|
+
ui.onToolCallEnd(call.name, result.result, result.error ? result.result : undefined, result.duration_ms);
|
|
1180
|
+
// ── Structured stream: tool result event ──
|
|
1181
|
+
if (options.responseStream) {
|
|
1182
|
+
options.responseStream.emit({
|
|
1183
|
+
type: 'tool_result',
|
|
1184
|
+
id: call.id,
|
|
1185
|
+
name: call.name,
|
|
1186
|
+
result: result.result,
|
|
1187
|
+
error: result.error ? result.result : undefined,
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1112
1190
|
// ── Feed Gödel detector with tool call data ──
|
|
1113
1191
|
loopDetector.recordToolCall(call.name, JSON.stringify(call.arguments || {}), result.result.slice(0, 500));
|
|
1114
|
-
// Post-tool hook
|
|
1115
|
-
runPostToolHook(call.name, call.arguments || {}, result.result, options.agent || 'kernel');
|
|
1116
1192
|
}
|
|
1117
1193
|
// ── Maintain conversation context across tool iterations ──
|
|
1118
1194
|
// 1. Include the assistant's response (its reasoning + which tools it chose)
|
|
@@ -1127,12 +1203,43 @@ Always quote file paths that contain spaces. Never reference internal system nam
|
|
|
1127
1203
|
return `${r.tool_call_id} (${toolCalls.find(tc => tc.id === r.tool_call_id)?.name || 'unknown'}): ${status}${compressed}`;
|
|
1128
1204
|
}).join('\n\n');
|
|
1129
1205
|
loopMessages.push({ role: 'user', content: `Tool results:\n${toolResultSummary}` });
|
|
1206
|
+
// ── Checkpoint: save agent state after tool execution ──
|
|
1207
|
+
checkpointManager.save({
|
|
1208
|
+
id: crypto.randomUUID(),
|
|
1209
|
+
sessionId,
|
|
1210
|
+
timestamp: Date.now(),
|
|
1211
|
+
iteration: i,
|
|
1212
|
+
messages: [...loopMessages],
|
|
1213
|
+
toolSequenceLog: [...toolSequenceLog],
|
|
1214
|
+
toolCallCount,
|
|
1215
|
+
cumulativeCostUsd,
|
|
1216
|
+
agentId: options.agent || 'kernel',
|
|
1217
|
+
model: lastResponse?.model || 'unknown',
|
|
1218
|
+
systemPrompt: systemContext,
|
|
1219
|
+
status: 'in_progress',
|
|
1220
|
+
}).then(() => {
|
|
1221
|
+
telemetry.emit('checkpoint_save', { iteration: i, toolCallCount });
|
|
1222
|
+
}).catch(() => {
|
|
1223
|
+
// Checkpoint save is non-blocking and non-critical
|
|
1224
|
+
});
|
|
1130
1225
|
}
|
|
1131
1226
|
catch (err) {
|
|
1132
|
-
|
|
1227
|
+
spinnerHandle?.stop();
|
|
1228
|
+
// ── Telemetry: session failure ──
|
|
1229
|
+
telemetry.emit('session_end', { status: 'failed', error: String(err), toolCallCount });
|
|
1230
|
+
telemetry.destroy().catch(() => { });
|
|
1133
1231
|
throw err;
|
|
1134
1232
|
}
|
|
1135
1233
|
}
|
|
1234
|
+
// ── Checkpoint & Telemetry: session ended (loop exhausted or early break) ──
|
|
1235
|
+
checkpointManager.markCompleted(sessionId).catch(() => { });
|
|
1236
|
+
telemetry.emit('session_end', {
|
|
1237
|
+
status: 'completed',
|
|
1238
|
+
toolCallCount,
|
|
1239
|
+
cumulativeCostUsd,
|
|
1240
|
+
reason: 'loop_exhausted',
|
|
1241
|
+
});
|
|
1242
|
+
telemetry.destroy().catch(() => { });
|
|
1136
1243
|
const content = lastResponse?.content || 'Reached maximum tool iterations.';
|
|
1137
1244
|
return {
|
|
1138
1245
|
content,
|
|
@@ -1205,4 +1312,36 @@ export async function runAndPrint(message, options = {}) {
|
|
|
1205
1312
|
process.exit(1);
|
|
1206
1313
|
}
|
|
1207
1314
|
}
|
|
1315
|
+
/**
|
|
1316
|
+
* Resume an agent session from a checkpoint.
|
|
1317
|
+
* Restores conversation messages and state, then continues execution.
|
|
1318
|
+
*/
|
|
1319
|
+
export async function runAgentFromCheckpoint(checkpoint, options = {}) {
|
|
1320
|
+
const telemetryInstance = new TelemetryEmitter(checkpoint.sessionId);
|
|
1321
|
+
telemetryInstance.emit('checkpoint_resume', {
|
|
1322
|
+
checkpointId: checkpoint.id,
|
|
1323
|
+
iteration: checkpoint.iteration,
|
|
1324
|
+
toolCallCount: checkpoint.toolCallCount,
|
|
1325
|
+
cumulativeCostUsd: checkpoint.cumulativeCostUsd,
|
|
1326
|
+
});
|
|
1327
|
+
printInfo(`Resuming from checkpoint (iteration ${checkpoint.iteration}, ${checkpoint.toolCallCount} tool calls, $${checkpoint.cumulativeCostUsd.toFixed(4)})`);
|
|
1328
|
+
// Restore conversation history from checkpoint messages
|
|
1329
|
+
const { restoreHistory } = await import('./memory.js');
|
|
1330
|
+
const turns = checkpoint.messages.map((m) => ({
|
|
1331
|
+
role: m.role,
|
|
1332
|
+
content: m.content,
|
|
1333
|
+
}));
|
|
1334
|
+
restoreHistory(turns);
|
|
1335
|
+
// Extract the original user message from the first user message in checkpoint
|
|
1336
|
+
const firstUserMsg = checkpoint.messages.find((m) => m.role === 'user');
|
|
1337
|
+
const message = firstUserMsg?.content || 'continue';
|
|
1338
|
+
// Re-run the agent with the restored context
|
|
1339
|
+
const response = await runAgent(message, {
|
|
1340
|
+
...options,
|
|
1341
|
+
agent: checkpoint.agentId || options.agent,
|
|
1342
|
+
skipPlanner: true, // Don't re-plan, just continue execution
|
|
1343
|
+
});
|
|
1344
|
+
await telemetryInstance.destroy();
|
|
1345
|
+
return response;
|
|
1346
|
+
}
|
|
1208
1347
|
//# sourceMappingURL=agent.js.map
|