@infinityi/engine-lib 1.0.0 → 1.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infinityi/engine-lib",
3
- "version": "1.0.0",
3
+ "version": "1.3.1",
4
4
  "description": "Agent infrastructure for TypeScript, built on @infinityi/forge.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,24 +0,0 @@
1
- # Examples
2
-
3
- Small, self-contained programs demonstrating the engine-lib API. Each one runs
4
- **offline** with `bun` — they use the network-free test doubles from
5
- `@infinityi/engine-lib/testing` (scripted providers) so no API key is required.
6
-
7
- ```bash
8
- bun examples/incident-analysis.ts # context injection + a read-only tool
9
- bun examples/terminal-coder.ts # streaming tokens + a persisted session
10
- bun examples/multi-agent.ts # handoff/delegation + sub-agent-as-tool
11
- bun examples/lifecycle.ts # forge.boot with agentRuntimeComponent
12
- ```
13
-
14
- | File | Demonstrates |
15
- | --- | --- |
16
- | [`incident-analysis.ts`](./incident-analysis.ts) | `defineAgent` + `defineTool`, `staticContext` injection, `onEvent` tool-call observation |
17
- | [`terminal-coder.ts`](./terminal-coder.ts) | streaming (`stream: true`) `token` events, `createSession` history persistence |
18
- | [`multi-agent.ts`](./multi-agent.ts) | Phase 7 — `handoffs` / `transfer_to_<name>` and `asTool(agent)` |
19
- | [`lifecycle.ts`](./lifecycle.ts) | Phase 8 — `agentRuntimeComponent` start/healthcheck/stop under `forge.boot` |
20
-
21
- > The examples import from `@infinityi/engine-lib`, so they work both inside this
22
- > repository and from the published package. In your own application, pass a real
23
- > provider, e.g. `createOpenAI({ apiKey, model })` or
24
- > `createAnthropic({ apiKey, model })`.
@@ -1,100 +0,0 @@
1
- /**
2
- * Example 1 — incident analysis.
3
- *
4
- * A monitoring component detects a crash and asks an "incident analyst" agent to
5
- * investigate. Recent logs are injected as run-time context, and the agent is
6
- * given a read-only `fetch_recent_logs` tool. Mirrors README "Example 1".
7
- *
8
- * Run it: `bun examples/incident-analysis.ts`
9
- *
10
- * In your own app, swap in a real provider such as
11
- * `createAnthropic({ apiKey, model })`. This example uses a scripted provider so
12
- * it runs offline, with no API key.
13
- */
14
-
15
- import { defineAgent } from "@infinityi/engine-lib/agent";
16
- import { runAgent } from "@infinityi/engine-lib/execution";
17
- import { staticContext } from "@infinityi/engine-lib/context";
18
- import { defineTool } from "@infinityi/engine-lib/tools";
19
- import { s } from "@infinityi/engine-lib/schema";
20
- import {
21
- scriptedProvider,
22
- textResult,
23
- toolCallResult,
24
- } from "@infinityi/engine-lib/testing";
25
-
26
- // A read-only tool the agent may call. In a real deployment `execute` would hit
27
- // your log store; here it returns a fixed slice.
28
- const fetchRecentLogs = defineTool({
29
- name: "fetch_recent_logs",
30
- description: "Fetch the last N log lines for a service.",
31
- parameters: s.object({
32
- service: s.string(),
33
- lines: s.optional(s.number({ int: true })),
34
- }),
35
- execute: ({ service, lines }) => ({
36
- ok: true,
37
- content: [
38
- `[${service}] OutOfMemoryError: Java heap space`,
39
- `[${service}] GC overhead limit exceeded (${lines ?? 200} lines scanned)`,
40
- ].join("\n"),
41
- }),
42
- });
43
-
44
- // Real provider (swap in for production):
45
- // import { createAnthropic } from "@infinityi/engine-lib/providers";
46
- // const provider = createAnthropic({ apiKey, model: "claude-sonnet-4" });
47
- // Scripted provider: turn 1 calls the tool, turn 2 produces the analysis.
48
- const provider = scriptedProvider([
49
- toolCallResult([
50
- {
51
- id: "c1",
52
- name: "fetch_recent_logs",
53
- arguments: { service: "checkout", lines: 200 },
54
- },
55
- ]),
56
- textResult(
57
- "Root cause: the checkout service ran out of heap (OutOfMemoryError), confirmed " +
58
- "by the GC overhead messages in the logs. Next steps: raise -Xmx, capture a heap " +
59
- "dump on OOM, and review the recent deploy for an unbounded cache.",
60
- ),
61
- ]);
62
-
63
- const incidentAnalyst = defineAgent({
64
- name: "incident-analyst",
65
- provider,
66
- instructions:
67
- "You are an SRE assistant. Diagnose the likely root cause of the crash and " +
68
- "propose concrete next steps. Cite the log lines you relied on.",
69
- tools: [fetchRecentLogs],
70
- });
71
-
72
- async function onServerCrash(event: {
73
- service: string;
74
- exitCode: number;
75
- timestamp: string;
76
- version: string;
77
- }) {
78
- const result = await runAgent(incidentAnalyst, {
79
- input: `Service "${event.service}" crashed with exit code ${event.exitCode}.`,
80
- context: [
81
- staticContext({
82
- crashedAt: event.timestamp,
83
- deployedVersion: event.version,
84
- }),
85
- ],
86
- onEvent: (e) => {
87
- if (e.type === "tool.call") console.log(` ↻ tool call: ${e.name}`);
88
- },
89
- });
90
- console.log("\n--- incident analysis ---");
91
- console.log(result.output);
92
- console.log(`\n(steps: ${result.steps}, agent: ${result.agent})`);
93
- }
94
-
95
- await onServerCrash({
96
- service: "checkout",
97
- exitCode: 137,
98
- timestamp: new Date().toISOString(),
99
- version: "2.4.1",
100
- });
@@ -1,53 +0,0 @@
1
- /**
2
- * Example 4 — Forge lifecycle integration (Phase 8).
3
- *
4
- * Boot the engine-lib runtime as a `@infinityi/forge/lifecycle` component:
5
- * `agentRuntimeComponent` validates providers on start, exposes a health probe,
6
- * and runs an `onStop` hook on graceful shutdown — all orchestrated by
7
- * `forge.boot`.
8
- *
9
- * Run it: `bun examples/lifecycle.ts`
10
- *
11
- * Uses in-memory doubles so it runs offline. `installSignals: false` + a no-op
12
- * `exit` keep the example from installing real process signal handlers.
13
- */
14
-
15
- import { boot } from "@infinityi/forge/lifecycle";
16
-
17
- import { agentRuntimeComponent } from "@infinityi/engine-lib/lifecycle";
18
- import {
19
- inMemorySessionStore,
20
- mockProvider,
21
- } from "@infinityi/engine-lib/testing";
22
-
23
- const store = inMemorySessionStore();
24
- const runtime = agentRuntimeComponent({
25
- providers: [mockProvider({ name: "openai", defaultModel: "gpt-5" })],
26
- sessionStore: store,
27
- // A real probe would issue a cheap completion; here it's a no-op success.
28
- probe: () => Promise.resolve(),
29
- probeOnStart: true,
30
- onStop: () => console.log(" onStop: flushing session store"),
31
- });
32
-
33
- const app = await boot({
34
- components: [runtime],
35
- installSignals: false,
36
- exit: () => {},
37
- });
38
- console.log(
39
- "booted — ready:",
40
- app.ready,
41
- "| components:",
42
- app.components.map((c) => c.name),
43
- );
44
-
45
- const health = await runtime.healthcheck?.({
46
- signal: new AbortController().signal,
47
- logger: console,
48
- });
49
- console.log("healthcheck:", health?.status, health?.data);
50
-
51
- await app.stop("example-complete");
52
- await app.done;
53
- console.log("drained cleanly");
@@ -1,93 +0,0 @@
1
- /**
2
- * Example 3 — multi-agent coordination (Phase 7).
3
- *
4
- * Two complementary composition patterns, both driven by the same `runAgent`
5
- * loop (no separate orchestrator):
6
- * 1. Handoff/delegation — a triage agent transfers the conversation to a
7
- * specialist via a synthetic `transfer_to_<name>` tool.
8
- * 2. Sub-agent-as-tool — a lead agent invokes a researcher agent through the
9
- * normal tool-calling path with `asTool(...)`.
10
- *
11
- * Run it: `bun examples/multi-agent.ts`
12
- *
13
- * Uses scripted providers so it runs offline.
14
- */
15
-
16
- import { asTool, defineAgent } from "@infinityi/engine-lib/agent";
17
- import { runAgent } from "@infinityi/engine-lib/execution";
18
- import {
19
- scriptedProvider,
20
- textResult,
21
- toolCallResult,
22
- } from "@infinityi/engine-lib/testing";
23
-
24
- // --- 1. Handoff / delegation ---------------------------------------------
25
-
26
- const billing = defineAgent({
27
- name: "billing",
28
- provider: scriptedProvider([
29
- textResult("I've issued your refund — it'll land in 3-5 days."),
30
- ]),
31
- instructions: "Handle billing and refunds.",
32
- });
33
-
34
- // Triage's model calls the synthetic `transfer_to_billing` tool to hand off.
35
- const triage = defineAgent({
36
- name: "triage",
37
- provider: scriptedProvider([
38
- toolCallResult([{ id: "h1", name: "transfer_to_billing", arguments: {} }]),
39
- ]),
40
- instructions: "Route the user to the right specialist.",
41
- handoffs: [billing],
42
- });
43
-
44
- const handoffResult = await runAgent(triage, { input: "I want a refund" });
45
- console.log("=== handoff ===");
46
- console.log("answer:", handoffResult.output);
47
- console.log(
48
- "final agent:",
49
- handoffResult.agent,
50
- "| trail:",
51
- handoffResult.handoffs,
52
- );
53
-
54
- // --- 2. Sub-agent-as-tool -------------------------------------------------
55
-
56
- const researcher = defineAgent({
57
- name: "researcher",
58
- provider: scriptedProvider([
59
- textResult(
60
- "Bun is a fast all-in-one JS runtime, bundler, and test runner.",
61
- ),
62
- ]),
63
- instructions: "Research deeply and report concisely.",
64
- });
65
-
66
- const lead = defineAgent({
67
- name: "lead",
68
- // Turn 1: delegate to the researcher tool. Turn 2: summarize its finding.
69
- provider: scriptedProvider([
70
- toolCallResult([
71
- { id: "c1", name: "researcher", arguments: { input: "What is Bun?" } },
72
- ]),
73
- textResult(
74
- "Summary: Bun is a fast all-in-one JavaScript runtime/bundler/test-runner.",
75
- ),
76
- ]),
77
- instructions: "Delegate research, then summarize.",
78
- tools: [
79
- asTool(researcher, { description: "Delegate research to a specialist." }),
80
- ],
81
- });
82
-
83
- const childEvents: string[] = [];
84
- const toolResult = await runAgent(lead, {
85
- input: "Give me a one-line summary of Bun.",
86
- onEvent: (e) => {
87
- if (e.type === "agent.child")
88
- childEvents.push(`${e.agent}@depth${e.depth}: ${e.event.type}`);
89
- },
90
- });
91
- console.log("\n=== sub-agent-as-tool ===");
92
- console.log("answer:", toolResult.output);
93
- console.log("child events:", childEvents.length, "(e.g.", childEvents[0] + ")");
@@ -1,80 +0,0 @@
1
- /**
2
- * Example 2 — terminal coder.
3
- *
4
- * A coding terminal streams tokens to the screen, persists the conversation in a
5
- * session (so history carries across prompts), and lets the agent call
6
- * file/command tools. Mirrors README "Example 2".
7
- *
8
- * Run it: `bun examples/terminal-coder.ts`
9
- *
10
- * Uses a scripted provider so it runs offline. In an app, swap in a real
11
- * provider such as `createOpenAI({ apiKey, model })`.
12
- */
13
-
14
- import { defineAgent } from "@infinityi/engine-lib/agent";
15
- import { runAgent } from "@infinityi/engine-lib/execution";
16
- import { createSession } from "@infinityi/engine-lib/session";
17
- import { defineTool } from "@infinityi/engine-lib/tools";
18
- import { s } from "@infinityi/engine-lib/schema";
19
- import {
20
- scriptedProvider,
21
- textResult,
22
- toolCallResult,
23
- } from "@infinityi/engine-lib/testing";
24
-
25
- const readFile = defineTool({
26
- name: "read_file",
27
- description: "Read a file from the workspace.",
28
- parameters: s.object({ path: s.string() }),
29
- execute: ({ path }) => ({
30
- ok: true,
31
- content: `// ${path}\nexport const answer = 42;\n`,
32
- }),
33
- });
34
-
35
- const runCommand = defineTool({
36
- name: "run_command",
37
- description: "Run a shell command in the workspace.",
38
- parameters: s.object({ command: s.string() }),
39
- execute: ({ command }) => ({ ok: true, content: `$ ${command}\nok` }),
40
- });
41
-
42
- const provider = scriptedProvider([
43
- toolCallResult([
44
- { id: "c1", name: "read_file", arguments: { path: "src/index.ts" } },
45
- ]),
46
- textResult(
47
- "`src/index.ts` exports `answer = 42`. Want me to add a test for it?",
48
- ),
49
- ]);
50
-
51
- const coder = defineAgent({
52
- name: "terminal-coder",
53
- provider,
54
- instructions:
55
- "You are a coding assistant operating inside the user's terminal.",
56
- tools: [readFile, runCommand],
57
- });
58
-
59
- // One terminal tab = one session, so history persists across prompts (backed by
60
- // the built-in InMemorySessionStore here).
61
- const session = createSession({ id: "tab-1" });
62
-
63
- async function onUserPrompt(prompt: string) {
64
- process.stdout.write(`\n> ${prompt}\n`);
65
- const stream = runAgent(coder, { input: prompt, session, stream: true });
66
- for await (const event of stream) {
67
- if (event.type === "token") process.stdout.write(event.delta); // live output
68
- if (event.type === "tool.call")
69
- process.stdout.write(`\n ↻ ${event.name}\n`); // tool spinner
70
- }
71
- const result = await stream.completed;
72
- // `result.messages` is the full run history (incl. the system instruction);
73
- // the session persists the new turn's messages, which `session.messages()` replays.
74
- const persisted = await session.messages();
75
- process.stdout.write(
76
- `\n (turn done — ${result.messages.length} messages in history, ${persisted.length} persisted)\n`,
77
- );
78
- }
79
-
80
- await onUserPrompt("What does src/index.ts export?");