loopengine 0.1.12 → 0.1.13
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/core/agent-config.d.ts +16 -0
- package/dist/core/llm-summarizer.d.ts +24 -0
- package/dist/core/llm-summarizer.js +42 -0
- package/dist/core/run-agent.js +6 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/package.json +3 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Rule, Decision, Scope } from 'actauth';
|
|
2
2
|
import type { Redis } from 'ioredis';
|
|
3
3
|
import type { SafetyClassifier } from 'toollane';
|
|
4
|
+
import type { Summarizer } from './compaction.js';
|
|
4
5
|
/** Which channel a runAgent() call is on — the value RunAgentOptions.channel
|
|
5
6
|
* carries, checked against directly by AgentConfig.httpNotifier's own
|
|
6
7
|
* resolution (see its own doc comment for why it only ever matches
|
|
@@ -443,6 +444,21 @@ export interface AgentConfig {
|
|
|
443
444
|
skillsDirs?: string[];
|
|
444
445
|
skillIndexBudgetTokens?: number;
|
|
445
446
|
contextBudgetTokens?: number;
|
|
447
|
+
/** How compaction.ts's Compactor compresses old history once a turn
|
|
448
|
+
* goes over contextBudgetTokens. Omitted entirely defaults to
|
|
449
|
+
* TruncatingSummarizer — a real, dependency-free fallback that just
|
|
450
|
+
* concatenates and cuts text, with no model call and no added latency
|
|
451
|
+
* or cost. Pass `new LLMSummarizer({ modelCall })` (llm-summarizer.js)
|
|
452
|
+
* to compact with a real model call instead — genuinely worth it for
|
|
453
|
+
* an agent whose sessions run long enough to hit compaction at all,
|
|
454
|
+
* since a fact stated once early on (an order number, an id) tends to
|
|
455
|
+
* survive a structured LLM summary but not a hard character cutoff.
|
|
456
|
+
* Not defaulted to LLMSummarizer automatically: that would add a
|
|
457
|
+
* hidden extra model call — cost, latency, and a new failure mode —
|
|
458
|
+
* to every agent, including ones that never expected compaction to do
|
|
459
|
+
* anything but this repo's own tests, which assert exact modelCall
|
|
460
|
+
* call counts. */
|
|
461
|
+
summarizer?: Summarizer;
|
|
446
462
|
/** Hard cap on model calls in one runAgent() invocation — the only thing
|
|
447
463
|
* that stops a model stuck re-requesting the same (or ping-ponging)
|
|
448
464
|
* tool calls forever, which nothing else in this loop bounds. Default
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Message } from './budget.js';
|
|
2
|
+
import type { ModelCall } from './run-agent.js';
|
|
3
|
+
import { type Summarizer } from './compaction.js';
|
|
4
|
+
export interface LLMSummarizerOptions {
|
|
5
|
+
modelCall: ModelCall;
|
|
6
|
+
/** Replaces the default instructions entirely — not appended to them. */
|
|
7
|
+
systemPrompt?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Calls modelCall with no tools and asks it to compact `messages` per
|
|
10
|
+
* DEFAULT_SYSTEM_PROMPT's own structure (see that constant's own doc
|
|
11
|
+
* comment for why "facts established" is its own named section rather
|
|
12
|
+
* than left to a generic "summarize this" prompt — a fact mentioned once
|
|
13
|
+
* early in a long conversation is exactly what a free-form summary tends
|
|
14
|
+
* to paraphrase away). Falls back to TruncatingSummarizer — rather than
|
|
15
|
+
* throwing, which would surface as a whole turn failing — if the call
|
|
16
|
+
* itself throws (rate limit, network) or comes back with no usable text
|
|
17
|
+
* (a model that only ever returns tool_use has nothing this can use). */
|
|
18
|
+
export declare class LLMSummarizer implements Summarizer {
|
|
19
|
+
private readonly modelCall;
|
|
20
|
+
private readonly systemPrompt;
|
|
21
|
+
private readonly fallback;
|
|
22
|
+
constructor(options: LLMSummarizerOptions);
|
|
23
|
+
summarize(messages: Message[]): Promise<Message>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { TruncatingSummarizer } from './compaction.js';
|
|
2
|
+
const DEFAULT_SYSTEM_PROMPT = `You are compacting an in-progress agent conversation to free up context window. You will be given a segment of older messages (the most recent messages are kept verbatim elsewhere and are not shown to you). Write a dense summary that lets the agent continue this task without having seen the original messages.
|
|
3
|
+
|
|
4
|
+
Structure your summary with these sections, using only the ones that have content:
|
|
5
|
+
- Facts established: concrete values stated even once — ids, numbers, names, dates, amounts, decisions — verbatim, not paraphrased. A fact that only appears here and gets paraphrased or dropped is lost for good.
|
|
6
|
+
- Actions taken: tool calls made and their outcomes, briefly.
|
|
7
|
+
- Open question / next step: what's still unresolved, if anything.
|
|
8
|
+
|
|
9
|
+
Output only the summary itself — no preamble, no "here is a summary".`;
|
|
10
|
+
/** Calls modelCall with no tools and asks it to compact `messages` per
|
|
11
|
+
* DEFAULT_SYSTEM_PROMPT's own structure (see that constant's own doc
|
|
12
|
+
* comment for why "facts established" is its own named section rather
|
|
13
|
+
* than left to a generic "summarize this" prompt — a fact mentioned once
|
|
14
|
+
* early in a long conversation is exactly what a free-form summary tends
|
|
15
|
+
* to paraphrase away). Falls back to TruncatingSummarizer — rather than
|
|
16
|
+
* throwing, which would surface as a whole turn failing — if the call
|
|
17
|
+
* itself throws (rate limit, network) or comes back with no usable text
|
|
18
|
+
* (a model that only ever returns tool_use has nothing this can use). */
|
|
19
|
+
export class LLMSummarizer {
|
|
20
|
+
modelCall;
|
|
21
|
+
systemPrompt;
|
|
22
|
+
fallback = new TruncatingSummarizer();
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.modelCall = options.modelCall;
|
|
25
|
+
this.systemPrompt = options.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
26
|
+
}
|
|
27
|
+
async summarize(messages) {
|
|
28
|
+
const transcript = messages.map((m) => `[${m.role}] ${m.content}`).join('\n');
|
|
29
|
+
let text;
|
|
30
|
+
try {
|
|
31
|
+
const response = await this.modelCall([{ role: 'user', content: transcript }], this.systemPrompt, []);
|
|
32
|
+
text = response.content.find((block) => block.type === 'text')?.text?.trim();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// modelCall threw — fall through to the truncating fallback below,
|
|
36
|
+
// same as text staying undefined.
|
|
37
|
+
}
|
|
38
|
+
if (!text)
|
|
39
|
+
return this.fallback.summarize(messages);
|
|
40
|
+
return { role: 'system', content: `[compacted ${messages.length} earlier message(s)]\n${text}` };
|
|
41
|
+
}
|
|
42
|
+
}
|
package/dist/core/run-agent.js
CHANGED
|
@@ -336,7 +336,12 @@ async function buildTurnContext(config, modelCall, options) {
|
|
|
336
336
|
// 70000-token nudge point) and hardThreshold's 0.92 still leave real
|
|
337
337
|
// margin before hitting it.
|
|
338
338
|
const budgetTracker = new BudgetTracker({ budgetTokens: config.contextBudgetTokens ?? 100000 });
|
|
339
|
-
const compactor = new Compactor({
|
|
339
|
+
const compactor = new Compactor({
|
|
340
|
+
budgetTokens: config.contextBudgetTokens ?? 100000,
|
|
341
|
+
softThreshold: budgetTracker.softThreshold,
|
|
342
|
+
tailMessages,
|
|
343
|
+
summarizer: config.summarizer,
|
|
344
|
+
});
|
|
340
345
|
const rules = loadRules(config);
|
|
341
346
|
// AgentConfig.httpNotifier only ever stands in for the http channel —
|
|
342
347
|
// see its own doc comment for why cli/http_stream never consult it at
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,10 @@ export { discoverAgents, loadAgentModule, synthesizeCreateModelCall } from './co
|
|
|
24
24
|
export type { AgentModule } from './core/discover-agents.js';
|
|
25
25
|
export { agentAsTool } from './core/agent-as-tool.js';
|
|
26
26
|
export { resumeAgent, loadRules, loadDefaultTools, loadSubagentAsTools, systemTools, systemSkillsDir } from './core/run-agent.js';
|
|
27
|
+
export { Compactor, TruncatingSummarizer } from './core/compaction.js';
|
|
28
|
+
export type { Summarizer, RecoverResult, RecoverAction } from './core/compaction.js';
|
|
29
|
+
export { LLMSummarizer } from './core/llm-summarizer.js';
|
|
30
|
+
export type { LLMSummarizerOptions } from './core/llm-summarizer.js';
|
|
27
31
|
export { createCheckpointStore } from './core/durable-approvals.js';
|
|
28
32
|
export type { TurnCheckpoint, CheckpointStore, OutstandingItem } from './core/durable-approvals.js';
|
|
29
33
|
export { addGatewayTool, agentDir, disconnectComposioAccount, describeGatewayTools, listComposioConnections, listComposioTools, loadGatewayToolsFromDir, removeGatewayTool, removeGatewayToolSlug, GatewayToolExistsError, GatewayToolNotFoundError, } from './core/gateway-tools.js';
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,8 @@ export { agentAsTool } from './core/agent-as-tool.js';
|
|
|
29
29
|
// copy of adapters/http.ts (which, like agent-registry.ts, is meant to be
|
|
30
30
|
// owned/edited, not imported — see this file's own header comment).
|
|
31
31
|
export { resumeAgent, loadRules, loadDefaultTools, loadSubagentAsTools, systemTools, systemSkillsDir } from './core/run-agent.js';
|
|
32
|
+
export { Compactor, TruncatingSummarizer } from './core/compaction.js';
|
|
33
|
+
export { LLMSummarizer } from './core/llm-summarizer.js';
|
|
32
34
|
export { createCheckpointStore } from './core/durable-approvals.js';
|
|
33
35
|
export { addGatewayTool, agentDir, disconnectComposioAccount, describeGatewayTools, listComposioConnections, listComposioTools, loadGatewayToolsFromDir, removeGatewayTool, removeGatewayToolSlug, GatewayToolExistsError, GatewayToolNotFoundError, } from './core/gateway-tools.js';
|
|
34
36
|
export { WebhookNotifier } from './core/http-notify-triggers/webhook.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loopengine",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Runtime for tool-using AI agents with a transparent ReAct loop.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -59,6 +59,8 @@
|
|
|
59
59
|
"dist/core/budget.d.ts",
|
|
60
60
|
"dist/core/compaction.js",
|
|
61
61
|
"dist/core/compaction.d.ts",
|
|
62
|
+
"dist/core/llm-summarizer.js",
|
|
63
|
+
"dist/core/llm-summarizer.d.ts",
|
|
62
64
|
"dist/core/recovery.js",
|
|
63
65
|
"dist/core/recovery.d.ts",
|
|
64
66
|
"dist/core/http-notifier.js",
|