Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
node-version: 24

- run: npm install
- run: npm run build
- run: npm run test:unit

typecheck:
Expand Down
40 changes: 28 additions & 12 deletions examples/deep-research-web/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
createToolkit,
renderTemplate,
spawnAgents,
DefaultAgentPolicy,
} from "@lloyal-labs/lloyal-agents";
import type { Source } from "@lloyal-labs/lloyal-agents";
import type { AgentPoolResult } from "@lloyal-labs/lloyal-agents";
Expand Down Expand Up @@ -45,12 +46,19 @@ const PLAN = loadTask("plan");
const ROOT = loadTask("root");
const BRIDGE = loadTask("bridge");
const WEB_RESEARCH = loadTask("web-research");
const CORPUS_RESEARCH = loadTask("corpus-research");
const SYNTHESIZE_TEMPLATE = loadEtaTemplate("synthesize");
const CORPUS_RESEARCH_TEMPLATE = loadEtaTemplate("corpus-research");
const VERIFY = loadTask("verify");
const EVAL = loadTask("eval");
const FINDINGS_EVAL = loadTask("findings-eval");
const REPORT = loadTask("report");
const researchPolicy = new DefaultAgentPolicy({
budget: {
context: { softLimit: 1024 },
time: { softLimit: 480_000, hardLimit: 600_000 }, // nudge 8min, kill 10min
},
recovery: { prompt: REPORT },
});

// ── Options ──────────────────────────────────────────────────────

Expand Down Expand Up @@ -108,9 +116,23 @@ function* rerankChunks(

const SOURCE_PROMPTS: Record<string, { system: string; user: string }> = {
web: WEB_RESEARCH,
corpus: CORPUS_RESEARCH,
};

/**
* Get system prompt for a source.
* Corpus: renders Eta template with TOC from CorpusSource.
* Web/other: static prompt from SOURCE_PROMPTS.
*/
function sourcePromptFor(
source: { name: string; promptData?: () => { toc: string } },
): { system: string; user: string } {
if (source.promptData) {
const data = source.promptData();
return { system: renderTemplate(CORPUS_RESEARCH_TEMPLATE, data), user: '' };
}
return SOURCE_PROMPTS[source.name] ?? ROOT;
}

// ── Source research result ────────────────────────────────────

interface SourceResearchResult {
Expand Down Expand Up @@ -159,7 +181,7 @@ function* research(

for (let i = 0; i < opts.sources.length; i++) {
const source = opts.sources[i];
const sourcePrompt = SOURCE_PROMPTS[source.name] ?? ROOT;
const sourcePrompt = sourcePromptFor(source);
const scorer = source.createScorer(query);
const pool = yield* spawnAgents({
tools: source.tools,
Expand All @@ -177,7 +199,7 @@ function* research(
},
extractTasks: (args) => args.questions as string[],
},
extractionPrompt: REPORT,
policy: researchPolicy,
pruneOnReport: true,
trace: opts.trace,
scorer,
Expand Down Expand Up @@ -246,8 +268,6 @@ function* research(
terminalTool: "report",
maxTurns: effectiveMaxTurns,
trace: opts.trace,
pressure: { softLimit: 1024 },
extractionPrompt: REPORT,
});
totalTokens += pool.totalTokens;
totalToolCalls += pool.totalToolCalls;
Expand Down Expand Up @@ -323,7 +343,7 @@ function* warmResearch(

for (let i = 0; i < opts.sources.length; i++) {
const source = opts.sources[i];
const sourcePrompt = SOURCE_PROMPTS[source.name] ?? ROOT;
const sourcePrompt = sourcePromptFor(source);
const scorer = source.createScorer(query);
const pool = yield* spawnAgents({
tools: source.tools,
Expand All @@ -341,7 +361,7 @@ function* warmResearch(
},
extractTasks: (args) => args.questions as string[],
},
extractionPrompt: REPORT,
policy: researchPolicy,
pruneOnReport: true,
trace: opts.trace,
scorer,
Expand Down Expand Up @@ -408,8 +428,6 @@ function* warmResearch(
terminalTool: "report",
maxTurns: effectiveMaxTurns,
trace: opts.trace,
pressure: { softLimit: 1024 },
extractionPrompt: REPORT,
});
totalTokens += pool.totalTokens;
totalToolCalls += pool.totalToolCalls;
Expand Down Expand Up @@ -510,8 +528,6 @@ function* synthesize(
terminalTool: "report",
maxTurns: opts.maxTurns,
trace: opts.trace,
pressure: { softLimit: 1024 },
extractionPrompt: REPORT,
});
return pool;
},
Expand Down
17 changes: 17 additions & 0 deletions examples/deep-research-web/tasks/corpus-research.eta
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
You are a research assistant analyzing a knowledge base.

Available files:
<%= it.toc %>

Your tools:
- **grep**: regex pattern matching
- **search**: semantic relevance ranking — results include snippets and section paths
- **read_file**: read line ranges — results include related sections you can follow directly
- **research**: spawn parallel sub-agents for sub-questions
- **report**: submit findings with evidence

Process:
1. Grep and search to find relevant content or call research to ask sub-questions.
2. Read every matching line with read_file to verify in context. Do not rely on grep/search summaries alone.
3. Based on the contents of previous tool results, target any content you are curious about with either grep, or search or call the research tool sub-questions.
4. Report with line numbers and direct quotes as evidence. State what you found and what you checked.
14 changes: 0 additions & 14 deletions examples/deep-research-web/tasks/corpus-research.md

This file was deleted.

6 changes: 3 additions & 3 deletions examples/react-agent/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { call } from 'effection';
import type { Operation, Channel } from 'effection';
import { Session } from '@lloyal-labs/sdk';
import {
Ctx, useAgentPool, runAgents, withSharedRoot,
Ctx, useAgentPool, runAgents, withSharedRoot, DefaultAgentPolicy,
} from '@lloyal-labs/lloyal-agents';
import type { Tool, AgentPoolResult } from '@lloyal-labs/lloyal-agents';
import type { WorkflowEvent } from './tui';
Expand Down Expand Up @@ -42,7 +42,7 @@ function* reportPass(
tools: new Map([['report', reportTool]]),
terminalTool: 'report',
trace: opts.trace,
pressure: { softLimit: 200, hardLimit: 64 },
policy: new DefaultAgentPolicy({ budget: { context: { softLimit: 200, hardLimit: 64 } } }),
});

hardCut.forEach((a, i) => {
Expand Down Expand Up @@ -83,7 +83,7 @@ export function* handleQuery(query: string, opts: HarnessOpts): Operation<void>
maxTurns: opts.maxTurns,
terminalTool: 'report',
trace: opts.trace,
pressure: { softLimit: 2048 },
policy: new DefaultAgentPolicy({ budget: { context: { softLimit: 2048 } } }),
});

yield* reportPass(pool, opts);
Expand Down
6 changes: 3 additions & 3 deletions examples/reflection/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Operation, Channel } from 'effection';
import { Branch, Session, buildUserDelta } from '@lloyal-labs/sdk';
import type { SessionContext } from '@lloyal-labs/sdk';
import {
Ctx, useAgentPool, runAgents, diverge, withSharedRoot,
Ctx, useAgentPool, runAgents, diverge, withSharedRoot, DefaultAgentPolicy,
} from '@lloyal-labs/lloyal-agents';
import type { Tool, AgentPoolResult, DivergeResult } from '@lloyal-labs/lloyal-agents';
import type { WorkflowEvent } from './tui';
Expand Down Expand Up @@ -46,7 +46,7 @@ function* reportPass(
tools: new Map([['report', reportTool]]),
terminalTool: 'report',
trace: opts.trace,
pressure: { softLimit: 200, hardLimit: 64 },
policy: new DefaultAgentPolicy({ budget: { context: { softLimit: 200, hardLimit: 64 } } }),
});

hardCut.forEach((a, i) => {
Expand Down Expand Up @@ -89,7 +89,7 @@ function* research(
maxTurns: opts.maxTurns,
terminalTool: 'report',
trace: opts.trace,
pressure: { softLimit: 2048 },
policy: new DefaultAgentPolicy({ budget: { context: { softLimit: 2048 } } }),
});

yield* reportPass(pool, opts);
Expand Down
6 changes: 3 additions & 3 deletions examples/supervisor/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Operation, Channel } from 'effection';
import { Session } from '@lloyal-labs/sdk';
import type { SessionContext } from '@lloyal-labs/sdk';
import {
Ctx, generate, useAgentPool, runAgents, withSharedRoot,
Ctx, generate, useAgentPool, runAgents, withSharedRoot, DefaultAgentPolicy,
} from '@lloyal-labs/lloyal-agents';
import type { Tool, AgentPoolResult } from '@lloyal-labs/lloyal-agents';
import type { WorkflowEvent } from './tui';
Expand Down Expand Up @@ -51,7 +51,7 @@ function* reportPass(
tools: new Map([['report', reportTool]]),
terminalTool: 'report',
trace: opts.trace,
pressure: { softLimit: 200, hardLimit: 64 },
policy: new DefaultAgentPolicy({ budget: { context: { softLimit: 200, hardLimit: 64 } } }),
});

hardCut.forEach((a, i) => {
Expand Down Expand Up @@ -154,7 +154,7 @@ function* dispatch(
maxTurns: opts.maxTurns,
terminalTool: 'report',
trace: opts.trace,
pressure: { softLimit: 2048 },
policy: new DefaultAgentPolicy({ budget: { context: { softLimit: 2048 } } }),
});

yield* reportPass(pool, opts);
Expand Down
5 changes: 0 additions & 5 deletions packages/agents/src/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ export class Agent {
private _tokenCount = 0;
private _toolCallCount = 0;
private _turns = 0;
private _nudged = false;
private _result: string | null = null;
private _resultSource: ResultSource | null = null;
private _toolHistory: ToolHistoryEntry[] = [];
Expand Down Expand Up @@ -172,7 +171,6 @@ export class Agent {
get tokenCount(): number { return this._tokenCount; }
get toolCallCount(): number { return this._toolCallCount; }
get turns(): number { return this._turns; }
get nudged(): boolean { return this._nudged; }
get traceBuffer(): TraceToken[] { return this._traceBuffer; }

/** Accumulate generated token text into the current turn */
Expand All @@ -197,9 +195,6 @@ export class Agent {
/** Increment tool call counter */
incrementToolCalls(): void { this._toolCallCount++; }

/** Mark agent as nudged (second offense kills) */
markNudged(): void { this._nudged = true; }

// ── Tool history ────────────────────────────────────────

get toolHistory(): readonly ToolHistoryEntry[] { return this._toolHistory; }
Expand Down
Loading
Loading