@linnlabs/linnkit 0.8.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/CHANGELOG.md +84 -0
- package/LICENSE +21 -0
- package/README.md +178 -0
- package/README.zh-CN.md +182 -0
- package/dist/agent-invocation-BHcNfrBV.d.cts +30 -0
- package/dist/agent-invocation-BznDaXDs.d.ts +30 -0
- package/dist/agentEvents-DEB7Fy_J.d.cts +81 -0
- package/dist/agentEvents-DEB7Fy_J.d.ts +81 -0
- package/dist/agentSpec-EkmviZjy.d.cts +2621 -0
- package/dist/agentSpec-EkmviZjy.d.ts +2621 -0
- package/dist/ai-engine.types-BpeU_XQG.d.cts +158 -0
- package/dist/ai-engine.types-vZRnQcJa.d.ts +158 -0
- package/dist/audit-BaRUGaqv.d.cts +307 -0
- package/dist/audit-BaRUGaqv.d.ts +307 -0
- package/dist/audit-CtcfART1.d.ts +33 -0
- package/dist/audit-LeOrm2hX.d.cts +33 -0
- package/dist/checkpointMarker-DAI3wUQu.d.cts +8 -0
- package/dist/checkpointMarker-DAI3wUQu.d.ts +8 -0
- package/dist/cli.cjs +8028 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +4 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +8025 -0
- package/dist/cli.js.map +1 -0
- package/dist/context-manager.cjs +8704 -0
- package/dist/context-manager.cjs.map +1 -0
- package/dist/context-manager.d.cts +2190 -0
- package/dist/context-manager.d.ts +2190 -0
- package/dist/context-manager.js +8650 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/context-trace-DRi5M4lX.d.ts +239 -0
- package/dist/context-trace-HE2qY5Q-.d.cts +239 -0
- package/dist/contracts.cjs +1333 -0
- package/dist/contracts.cjs.map +1 -0
- package/dist/contracts.d.cts +8 -0
- package/dist/contracts.d.ts +8 -0
- package/dist/contracts.js +1214 -0
- package/dist/contracts.js.map +1 -0
- package/dist/defaultGraphExecutor-BBswR8wn.d.ts +624 -0
- package/dist/defaultGraphExecutor-BIjJj7WF.d.cts +624 -0
- package/dist/execution-CAIypb41.d.cts +129 -0
- package/dist/execution-CAIypb41.d.ts +129 -0
- package/dist/index-CHqwkvGp.d.ts +149 -0
- package/dist/index-CJeWHopy.d.ts +584 -0
- package/dist/index-Cm-JbzTH.d.cts +1450 -0
- package/dist/index-Cvr23YCl.d.cts +23 -0
- package/dist/index-DDzuSb0n.d.ts +23 -0
- package/dist/index-DO4dQgf2.d.cts +584 -0
- package/dist/index-DRBWi1fy.d.ts +1450 -0
- package/dist/index-Dl5PLgAv.d.cts +149 -0
- package/dist/index.cjs +9577 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +89 -0
- package/dist/index.d.ts +89 -0
- package/dist/index.js +9563 -0
- package/dist/index.js.map +1 -0
- package/dist/messages-XthmnHZ3.d.cts +8007 -0
- package/dist/messages-XthmnHZ3.d.ts +8007 -0
- package/dist/ports-DaatKJXp.d.cts +90 -0
- package/dist/ports-DnLuKfpE.d.ts +90 -0
- package/dist/ports.cjs +4 -0
- package/dist/ports.cjs.map +1 -0
- package/dist/ports.d.cts +7 -0
- package/dist/ports.d.ts +7 -0
- package/dist/ports.js +3 -0
- package/dist/ports.js.map +1 -0
- package/dist/quickstart.cjs +7697 -0
- package/dist/quickstart.cjs.map +1 -0
- package/dist/quickstart.d.cts +24 -0
- package/dist/quickstart.d.ts +24 -0
- package/dist/quickstart.js +7691 -0
- package/dist/quickstart.js.map +1 -0
- package/dist/runAgent-CPj_9e58.d.ts +88 -0
- package/dist/runAgent-HYKlXbVr.d.cts +88 -0
- package/dist/runHandle-CyXvzgzk.d.ts +239 -0
- package/dist/runHandle-D3gPsD7B.d.cts +239 -0
- package/dist/runtime-kernel/events.cjs +1485 -0
- package/dist/runtime-kernel/events.cjs.map +1 -0
- package/dist/runtime-kernel/events.d.cts +8 -0
- package/dist/runtime-kernel/events.d.ts +8 -0
- package/dist/runtime-kernel/events.js +1475 -0
- package/dist/runtime-kernel/events.js.map +1 -0
- package/dist/runtime-kernel.cjs +8656 -0
- package/dist/runtime-kernel.cjs.map +1 -0
- package/dist/runtime-kernel.d.cts +19 -0
- package/dist/runtime-kernel.d.ts +19 -0
- package/dist/runtime-kernel.js +8568 -0
- package/dist/runtime-kernel.js.map +1 -0
- package/dist/sse-vPyrOPa0.d.cts +1687 -0
- package/dist/sse-vPyrOPa0.d.ts +1687 -0
- package/dist/testkit.cjs +10613 -0
- package/dist/testkit.cjs.map +1 -0
- package/dist/testkit.d.cts +284 -0
- package/dist/testkit.d.ts +284 -0
- package/dist/testkit.js +10593 -0
- package/dist/testkit.js.map +1 -0
- package/dist/todo-B1PmDlp3.d.cts +2253 -0
- package/dist/todo-B1PmDlp3.d.ts +2253 -0
- package/dist/tokenizer-DFL4I7-I.d.ts +28 -0
- package/dist/tokenizer-DH_JXv-H.d.cts +28 -0
- package/dist/toolContracts-Blll0241.d.ts +463 -0
- package/dist/toolContracts-CLkQmhTG.d.cts +463 -0
- package/docs/README.md +76 -0
- package/docs/integration/01-installation.md +94 -0
- package/docs/integration/02-quickstart.md +104 -0
- package/docs/integration/README.md +223 -0
- package/docs/integration/agent-registration-guide.md +330 -0
- package/docs/integration/audit.md +64 -0
- package/docs/integration/child-runs.md +87 -0
- package/docs/integration/constraints-and-pitfalls.md +87 -0
- package/docs/integration/context-engineering.md +650 -0
- package/docs/integration/context-fences.md +289 -0
- package/docs/integration/glossary.md +69 -0
- package/docs/integration/llm-provider.md +76 -0
- package/docs/integration/persistence.md +44 -0
- package/docs/integration/realtime.md +76 -0
- package/docs/integration/run-supervisor.md +69 -0
- package/docs/integration/telemetry.md +48 -0
- package/docs/integration/testing.md +95 -0
- package/docs/integration/tool-development-guide.md +362 -0
- package/docs/integration/tool-history.md +202 -0
- package/docs/integration/tools.md +188 -0
- package/package.json +115 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
> **Note**: linnkit is in `0.x` — minor versions may introduce new public exports
|
|
9
|
+
> but patch versions should remain compatible.
|
|
10
|
+
>
|
|
11
|
+
> Versions before 0.5.0 were internal alpha and are summarized only at a high level here.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## [Unreleased]
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## [0.8.0] - 2026-05-13
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- `TokenizerPort` interface in `@linnlabs/linnkit/ports` — host-injectable token estimation contract
|
|
24
|
+
- `DefaultTokenizerPort` + `createDefaultTokenizerPort(config)` in `@linnlabs/linnkit/runtime-kernel` — wraps the existing `TokenCalculator` (tiktoken + char-ratio fallback) behind the new interface
|
|
25
|
+
- `ContextManagerBaseOptions.tokenizer` / `tokenizerModelId` on `AgentContextManager`, `ChatContextManager`, `AgentMessageOrchestrator`, `ChatMessageOrchestrator` — inject once at assembly time, drives all budget decisions
|
|
26
|
+
- `updateTokenizerModelId(modelId)` on `ContextManagerBase` — required when reusing one context manager across multiple models
|
|
27
|
+
- `createMockTokenizerPort()` in `@linnlabs/linnkit/testkit` — fixed-token-per-message mock for deterministic budget / trimming tests
|
|
28
|
+
- `C12_HOST_TOKENIZER_DRIVES_BUDGET` strict invariant in testkit `context-harness` — proves injected tokenizer actually drives `message-decision.tokens` and `trace.finalTokens`
|
|
29
|
+
|
|
30
|
+
### Compatibility
|
|
31
|
+
|
|
32
|
+
- Non-breaking. Hosts not injecting `tokenizer` continue using `TokenCalculator` with 0.7.x behavior unchanged.
|
|
33
|
+
- `contextPolicy.tokenEstimation` (encoding / avgCharsPerToken / toolCallOverhead) continues to configure the default tokenizer when no custom tokenizer is injected.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## [0.7.0] - 2026-05-12
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- `defineAgent` / `runAgent` / `defineConfig` quickstart helpers
|
|
42
|
+
- `@linnlabs/linnkit/quickstart` public sub-entrypoint
|
|
43
|
+
- CLI v0: `linnkit init` / `linnkit run` / `linnkit doctor`
|
|
44
|
+
- `README.zh-CN.md` Chinese documentation
|
|
45
|
+
|
|
46
|
+
### Compatibility
|
|
47
|
+
|
|
48
|
+
- Non-breaking. All 0.6.x public APIs remain unchanged.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## [0.6.0] - 2026-05-11
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
- 12-group `AgentSpec.contextPolicy`: `budget` / `toolHistory` / `toolOutput` / `providerReplay` / `summarization` / `mustKeep` / `workingMemory` / `checkpoint` / `reasoningRetention` / `tokenEstimation` / `systemReminder` / `contextTrace`
|
|
57
|
+
- `defineContextPolicy()` helper — merges defaults and validates group combination constraints
|
|
58
|
+
- `ContextTrace` machine-readable sidecar of every context build decision
|
|
59
|
+
- `SystemReminder` registry + trigger/template extension points
|
|
60
|
+
- `ContextCheckpointTool` / `createContextCheckpointTool()` — host-neutral active checkpoint tool
|
|
61
|
+
- 11 additional strict invariants in testkit `context-harness` (total: 26 — 15 run + 11 contextPolicy + C12 tokenizer added in 0.8.0)
|
|
62
|
+
- `docs/integration/` restructured: 18 topic-specific guides each with Front Matter
|
|
63
|
+
|
|
64
|
+
### Compatibility
|
|
65
|
+
|
|
66
|
+
- Non-breaking. Hosts using the pre-0.6.0 flat `contextPolicy` shape are auto-migrated via `defineContextPolicy()`.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## [0.5.0] - 2026-05-10
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
|
|
74
|
+
- `AgentSpec` — first-class serializable agent blueprint (id / version / capabilities / tools / contextPolicy / modelHints / audit / metadata)
|
|
75
|
+
- `RunSupervisor` + `RunHandle` v2: `cancel` / `observe` / `cost` / `spawnDetached` / `waitForTerminal` / `drain` / `recoverOnBoot`
|
|
76
|
+
- `invokeChildRun` — synchronous child run with cost roll-up to parent
|
|
77
|
+
- `AuditEnvelope` + `AuditPort` — structured logging for non-deterministic decisions
|
|
78
|
+
- Tool history compression: `per-pair` / `per-run` / `none` strategies + `overflowStrategy`
|
|
79
|
+
- testkit with 15 strict run invariants
|
|
80
|
+
- Documentation reorganized: 17 topic-specific guides under `docs/integration/`
|
|
81
|
+
|
|
82
|
+
### Compatibility
|
|
83
|
+
|
|
84
|
+
- First stable public API surface. Sub-entrypoints locked.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Linnlabs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# linnkit
|
|
2
|
+
|
|
3
|
+
**A fine-grained context engineering framework for Agent applications — control every token sent to the model, with clear run lifecycle, audit records, and testable protocol boundaries.**
|
|
4
|
+
|
|
5
|
+
[中文文档](./README.zh-CN.md) · [Integration Guide](./docs/integration/README.md) · [Changelog](./CHANGELOG.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What is linnkit?
|
|
10
|
+
|
|
11
|
+
linnkit is a foundational skeleton for Agent applications:
|
|
12
|
+
|
|
13
|
+
| Layer | Responsibility |
|
|
14
|
+
|-------|---------------|
|
|
15
|
+
| `runtime-kernel` | Run agents, run tools, manage run lifecycle, record events, handle cancellation and cost |
|
|
16
|
+
| `context-manager` | Build the context sent to the model, trim to budget, inject host context |
|
|
17
|
+
| `ports` | Interfaces the host must implement: LLM, tools, storage, tokenizer |
|
|
18
|
+
| `testkit` | Guard the protocol with tests, not oral agreements |
|
|
19
|
+
|
|
20
|
+
linnkit has no built-in LLM provider, no database binding, no UI, and no opinions on RAG, memory, permissions, or IM integrations. Those belong to your product.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Why use linnkit?
|
|
25
|
+
|
|
26
|
+
**Fine-grained context control** — Describe your entire context strategy declaratively with `AgentSpec.contextPolicy`. Configure token budget, tool history retention, summarization triggers, must-keep rules, checkpoint compression, reasoning retention, system reminder injection, observation truncation with full-copy archiving, provider sidecar replay, and custom tokenizer. The context sent to the model is not a hand-assembled `messages[]` array — it's a rule-driven, recorded build process.
|
|
27
|
+
|
|
28
|
+
**ContextTrace observability** — Every context build produces a machine-readable trace: which messages were kept, which were trimmed, why, how many tokens each step consumed, and whether the final result exceeded the budget. When the model answers incorrectly, you don't need to guess whether context was lost — you can read the trace directly.
|
|
29
|
+
|
|
30
|
+
**Managed run lifecycle** — `RunSupervisor` and `RunHandle` turn each agent invocation into a stateful run with its own `runId`, cancellation, observable event stream, state queries, cost accounting, synchronous child runs, and spawnable detached background runs. Agents behave like real services, not temporary function calls.
|
|
31
|
+
|
|
32
|
+
**Audit-first design** — `AuditEnvelope` and `AuditPort` capture important decisions — model selection, tool rejection, fallback, awaiting user input, sandbox decisions — into a unified audit stream. Not for appearances, but so you can answer: *why did the system do that?*
|
|
33
|
+
|
|
34
|
+
**Clean host boundaries via fence injection** — linnkit doesn't know what "document chunk", "knowledge base", or "project memory" means in your product. Hosts register their own context types as fence families. linnkit handles the rules: when to keep them, when to trim them, how to observe them — without hardcoding business vocabulary.
|
|
35
|
+
|
|
36
|
+
**Protocol invariants, not conventions** — linnkit's testkit enforces 26 strict invariants: final tokens must not exceed budget, tool calls and outputs must not be separated, must-keep messages must never be trimmed, run state must not stay `running` after termination, budget decisions must actually use the injected custom tokenizer... The more complex an Agent system becomes, the more these invariants protect you from small changes silently breaking the protocol.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## What problems does it solve?
|
|
41
|
+
|
|
42
|
+
If you've built Agent products before, you've likely run into these:
|
|
43
|
+
|
|
44
|
+
- Context is hard to manage — it's difficult to observe exactly what gets sent to the LLM each time.
|
|
45
|
+
- Long conversations make it unclear what the model actually sees.
|
|
46
|
+
- As tool calls accumulate, deciding what to keep vs. compress becomes guesswork.
|
|
47
|
+
- After a user cancels, run state, event stream, tool execution, and frontend UI can fall out of sync.
|
|
48
|
+
- When multiple agents call each other, cost, events, and errors across parent/child runs are hard to trace.
|
|
49
|
+
- A bug can't be reproduced because nobody recorded how context was trimmed at the time.
|
|
50
|
+
- Tests only check "did the final answer look right" but can't catch a broken protocol.
|
|
51
|
+
|
|
52
|
+
linnkit's goal is to turn these into configurable, observable, and testable engineering problems.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## What linnkit does NOT do
|
|
57
|
+
|
|
58
|
+
These capabilities matter, but they are not linnkit's responsibility:
|
|
59
|
+
|
|
60
|
+
- No built-in OpenAI / Claude / Gemini provider.
|
|
61
|
+
- No built-in RAG, vector store, knowledge base, or memory system.
|
|
62
|
+
- No built-in tools (search, file read/write, browser, IM).
|
|
63
|
+
- No built-in UI, console, or DevTools platform.
|
|
64
|
+
- No opinions on permissions, security policy, or billing strategy.
|
|
65
|
+
|
|
66
|
+
linnkit provides boundaries and protocols to make these easier to integrate. The implementations belong to your product.
|
|
67
|
+
|
|
68
|
+
This is what allows linnkit to serve multiple different host applications rather than becoming an internal framework for one specific product.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
Install:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm install @linnlabs/linnkit
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Create a demo host:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx linnkit init demo-agent
|
|
84
|
+
cd demo-agent
|
|
85
|
+
npm install
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
After configuring environment variables, check your setup:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npx linnkit doctor
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Run a hello agent:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npx linnkit run hello --input "Describe linnkit in one sentence"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This quickstart is for getting up and running quickly — it's not a production setup. Production hosts should assemble their own LLM, tools, storage, audit, and context policy by following the [integration guide](./docs/integration/README.md).
|
|
101
|
+
|
|
102
|
+
### One-line prompt for coding agents
|
|
103
|
+
|
|
104
|
+
If you use Claude Code, Codex, Cursor, Windsurf, or another coding agent, you can paste this directly:
|
|
105
|
+
|
|
106
|
+
> If linnkit is not cloned yet, clone https://github.com/linnlabs/linnkit first; then follow the README and `docs/integration/02-quickstart.md` to initialize a local demo host, prefer npm, run `linnkit doctor`, do not wire production storage or real business tools, and finish by telling me the next command to run plus which `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` settings are still missing.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Minimal code example
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { defineAgent, runAgent } from '@linnlabs/linnkit/quickstart';
|
|
114
|
+
|
|
115
|
+
const agent = defineAgent({
|
|
116
|
+
id: 'hello',
|
|
117
|
+
version: '0.1.0',
|
|
118
|
+
role: 'Assistant',
|
|
119
|
+
systemPrompt: 'You are a concise, reliable assistant.',
|
|
120
|
+
modelId: 'gpt-4o-mini',
|
|
121
|
+
capabilities: ['agent'],
|
|
122
|
+
tools: [],
|
|
123
|
+
contextPolicy: {
|
|
124
|
+
budget: { maxTokens: 16_000, reservedForResponse: 2_000 },
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const result = await runAgent(agent, { input: 'What is linnkit?', llm });
|
|
129
|
+
console.log(result.finalAnswer);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Public sub-entrypoints
|
|
135
|
+
|
|
136
|
+
| Sub-entrypoint | Purpose |
|
|
137
|
+
|---------------|---------|
|
|
138
|
+
| `@linnlabs/linnkit` | Root entry — exports main namespaces |
|
|
139
|
+
| `@linnlabs/linnkit/ports` | Interfaces the host must implement |
|
|
140
|
+
| `@linnlabs/linnkit/contracts` | Stable data structures: `AgentSpec`, `AiMessage`, `RuntimeEvent` |
|
|
141
|
+
| `@linnlabs/linnkit/runtime-kernel` | Graph engine, tool runtime, run supervisor |
|
|
142
|
+
| `@linnlabs/linnkit/runtime-kernel/events` | Browser-safe event governance pure functions |
|
|
143
|
+
| `@linnlabs/linnkit/context-manager` | Context build, fence registry, message formatter, context policy |
|
|
144
|
+
| `@linnlabs/linnkit/testkit` | Test harnesses and 26 protocol invariants |
|
|
145
|
+
| `@linnlabs/linnkit/quickstart` | Demo / development helpers |
|
|
146
|
+
|
|
147
|
+
> **Browser rule**: do not import `@linnlabs/linnkit/runtime-kernel` in a frontend bundle — it pulls in Node-only sub-trees. For frontend event display logic only, use `@linnlabs/linnkit/runtime-kernel/events`.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Documentation
|
|
152
|
+
|
|
153
|
+
| Document | Content |
|
|
154
|
+
|----------|---------|
|
|
155
|
+
| [docs/integration/README.md](./docs/integration/README.md) | Integration hub — start here |
|
|
156
|
+
| [docs/integration/01-installation.md](./docs/integration/01-installation.md) | Install and registry auth |
|
|
157
|
+
| [docs/integration/02-quickstart.md](./docs/integration/02-quickstart.md) | Quickstart demo |
|
|
158
|
+
| [docs/integration/agent-registration-guide.md](./docs/integration/agent-registration-guide.md) | Agent registration and `AgentSpec` |
|
|
159
|
+
| [docs/integration/context-engineering.md](./docs/integration/context-engineering.md) | Context policy, ContextTrace, TokenizerPort |
|
|
160
|
+
| [docs/integration/context-fences.md](./docs/integration/context-fences.md) | Host context injection |
|
|
161
|
+
| [docs/integration/tools.md](./docs/integration/tools.md) | Tool integration overview |
|
|
162
|
+
| [docs/integration/tool-development-guide.md](./docs/integration/tool-development-guide.md) | Tool design internals |
|
|
163
|
+
| [docs/integration/run-supervisor.md](./docs/integration/run-supervisor.md) | Run lifecycle management |
|
|
164
|
+
| [docs/integration/testing.md](./docs/integration/testing.md) | Testkit and invariants |
|
|
165
|
+
| [CHANGELOG.md](./CHANGELOG.md) | Public release history |
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Status
|
|
170
|
+
|
|
171
|
+
- **Version**: see [`package.json`](./package.json)
|
|
172
|
+
- **Distribution**: npmjs.com public registry
|
|
173
|
+
- **Stability**: `0.x` — public sub-entrypoints are locked; Context Engineering API stable since 0.6.0
|
|
174
|
+
- **Open source**: MIT-licensed source is available at <https://github.com/linnlabs/linnkit>
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT — see [LICENSE](./LICENSE).
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# linnkit
|
|
2
|
+
|
|
3
|
+
**linnkit 是一个可以方便地精细化管理上下文的 Agent 框架,追求控制发给LLM的每一个 token,同时保留清晰的运行生命周期、审计记录和测试边界。**
|
|
4
|
+
|
|
5
|
+
[English](./README.md) · [接入文档](./docs/integration/README.md) · [更新日志](./CHANGELOG.md)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## linnkit 是什么?
|
|
10
|
+
|
|
11
|
+
linnkit是一套 Agent 应用的底层骨架:
|
|
12
|
+
|
|
13
|
+
| 层 | 负责什么 |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `runtime-kernel` | 跑 agent、跑工具、管理 run、记录事件、处理取消和 cost |
|
|
16
|
+
| `context-manager` | 构建发给模型的上下文,按预算裁剪,注入 host 上下文 |
|
|
17
|
+
| `ports` | 接入方需要实现的接口,例如 LLM、工具、存储、tokenizer |
|
|
18
|
+
| `testkit` | 用测试守住协议,不靠口头约定 |
|
|
19
|
+
|
|
20
|
+
linnkit 不内置 LLM provider,不绑定数据库,不提供 UI,也不替你做 RAG、记忆、权限、IM 接入这些产品层能力。
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 为什么选 linnkit?
|
|
25
|
+
|
|
26
|
+
**精细化上下文控制** — 用 `AgentSpec.contextPolicy` 声明式地描述完整上下文策略:token 预算与预留回答空间、工具历史保留方式、摘要触发时机、必须保留的消息类型、checkpoint 压缩、推理内容保留、system reminder 注入、observation 截断与完整副本落盘、provider sidecar replay、自定义 tokenizer。发给模型的上下文不是手拼出来的 `messages[]`,而是一套有规则、有记录的构建过程。
|
|
27
|
+
|
|
28
|
+
**ContextTrace 可观测性** — 每次上下文构建都会产出一份机器可读的 trace:哪些消息被保留、哪些被裁、为什么裁、每一步消耗多少 token、最终是否超过预算。模型答错时,不用猜"是不是上下文丢了",直接看 trace。
|
|
29
|
+
|
|
30
|
+
**run 生命周期管理** — `RunSupervisor` 和 `RunHandle` 让每次 agent 调用变成一个有状态的 run:独立 `runId`、可取消、可观察事件流、可查询状态、可统计 cost、可跑同步子 run、可 spawn 后台 detached run。Agent 更接近真实服务,而不是临时函数调用。
|
|
31
|
+
|
|
32
|
+
**审计设计** — `AuditEnvelope` / `AuditPort` 把模型选择、工具拒绝、fallback、等待用户、sandbox 决策等重要行为纳入统一审计流。不是为了"看起来企业级",而是为了在出问题时能回答:当时系统为什么这么做?
|
|
33
|
+
|
|
34
|
+
**干净的 host 边界** — linnkit 不知道你的业务里什么叫"文档片段""知识库""项目记忆"。host 用 fence 机制注册自己的上下文类型,linnkit 负责按规则保留、裁剪、观测——不硬编码任何业务词汇。
|
|
35
|
+
|
|
36
|
+
**协议不变量测试** — testkit 强制校验 26 条严格不变量:final tokens 不能超预算、tool call 与 tool output 不能拆散、must-keep 消息不能被裁、run 结束后不能停在 running、注入自定义 tokenizer 后预算决策必须真的使用它……Agent 系统越复杂,越需要这些不变量防止小改动悄悄弄坏协议。
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 它适合解决什么问题?
|
|
41
|
+
|
|
42
|
+
如果你已经做过 Agent 产品,通常会遇到这些问题:
|
|
43
|
+
|
|
44
|
+
- 上下文不好管理,难以观测每次发给LLM的全部上下文。
|
|
45
|
+
- 对话越长,模型到底看到了什么说不清。
|
|
46
|
+
- 工具调用一多,哪些结果该保留、哪些该压缩,只能靠经验调。
|
|
47
|
+
- 用户点取消后,run 状态、事件流、工具执行和前端展示容易不同步。
|
|
48
|
+
- 多个 agent 互相调用后,父子 run 的 cost、事件和错误不好追。
|
|
49
|
+
- 一个 bug 复现不了,因为当时上下文是怎么裁剪的没人记录。
|
|
50
|
+
- 测试只测"最后回答像不像",但测不到协议是否坏了。
|
|
51
|
+
|
|
52
|
+
linnkit 的目标就是把这些事变成可配置、可观测、可测试的工程问题。
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## linnkit 不做什么?
|
|
57
|
+
|
|
58
|
+
这些能力很重要,但不属于 linnkit 的核心职责:
|
|
59
|
+
|
|
60
|
+
- 不内置 OpenAI / Claude / Gemini provider。
|
|
61
|
+
- 不内置 RAG、向量库、知识库、记忆系统。
|
|
62
|
+
- 不内置业务工具,例如搜索、读文件、写文件、浏览器、IM。
|
|
63
|
+
- 不内置 UI、控制台、DevTools 平台。
|
|
64
|
+
- 不替 host 决定权限、安全策略、计费策略。
|
|
65
|
+
|
|
66
|
+
linnkit 会提供边界和协议,让这些能力更容易接入;但具体实现应该属于你的产品。
|
|
67
|
+
|
|
68
|
+
它让 linnkit 可以被不同 host 使用,而不是变成某一个产品的内部框架。
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 5 分钟快速试用
|
|
73
|
+
|
|
74
|
+
安装:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm install @linnlabs/linnkit
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
创建 demo host:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx linnkit init demo-agent
|
|
84
|
+
cd demo-agent
|
|
85
|
+
npm install
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
配置环境变量后检查:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npx linnkit doctor
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
运行 hello agent:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npx linnkit run hello --input "用一句话介绍 linnkit"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
这个 quickstart 是为了让你快速跑起来,不代表生产接入方式。生产 host 应该按 [接入文档](./docs/integration/README.md) 装配自己的 LLM、工具、存储、审计和上下文策略。
|
|
101
|
+
|
|
102
|
+
### 一句话交给 Coding Agent 安装
|
|
103
|
+
|
|
104
|
+
如果你在用 Claude Code、Codex、Cursor、Windsurf 或其他 coding agent,可以直接把下面这句话发给它:
|
|
105
|
+
|
|
106
|
+
> 如果还没 clone linnkit,就先 clone https://github.com/linnlabs/linnkit;然后按 README 和 `docs/integration/02-quickstart.md` 初始化一个本地 demo host,优先使用 npm,运行 `linnkit doctor`,不要接入生产存储或真实业务工具,结束时告诉我下一条运行命令,以及还缺哪些 `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` 配置需要补充。
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 最小代码示例
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { defineAgent, runAgent } from '@linnlabs/linnkit/quickstart';
|
|
114
|
+
|
|
115
|
+
const agent = defineAgent({
|
|
116
|
+
id: 'hello',
|
|
117
|
+
version: '0.1.0',
|
|
118
|
+
role: '助手',
|
|
119
|
+
systemPrompt: '你是一个简洁、可靠的助手。',
|
|
120
|
+
modelId: 'gpt-4o-mini',
|
|
121
|
+
capabilities: ['agent'],
|
|
122
|
+
tools: [],
|
|
123
|
+
contextPolicy: {
|
|
124
|
+
budget: { maxTokens: 16_000, reservedForResponse: 2_000 },
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const result = await runAgent(agent, {
|
|
129
|
+
input: 'linnkit 是什么?',
|
|
130
|
+
llm,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
console.log(result.finalAnswer);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 公开入口
|
|
139
|
+
|
|
140
|
+
| 子入口 | 用途 |
|
|
141
|
+
|---|---|
|
|
142
|
+
| `@linnlabs/linnkit` | 根入口,导出主要 namespace |
|
|
143
|
+
| `@linnlabs/linnkit/ports` | host 需要实现的接口 |
|
|
144
|
+
| `@linnlabs/linnkit/contracts` | 稳定数据结构,例如 `AgentSpec`、`AiMessage`、`RuntimeEvent` |
|
|
145
|
+
| `@linnlabs/linnkit/runtime-kernel` | graph、tool runtime、run supervisor 等运行时能力 |
|
|
146
|
+
| `@linnlabs/linnkit/runtime-kernel/events` | 浏览器安全的事件治理函数 |
|
|
147
|
+
| `@linnlabs/linnkit/context-manager` | 上下文构建、fence、message formatter、context policy |
|
|
148
|
+
| `@linnlabs/linnkit/testkit` | 测试 harness 和协议不变量 |
|
|
149
|
+
| `@linnlabs/linnkit/quickstart` | demo / 试用辅助函数 |
|
|
150
|
+
|
|
151
|
+
注意:前端页面不要 import `@linnlabs/linnkit/runtime-kernel`,它包含 Node-only 子树。前端只需要事件展示规则时,用 `@linnlabs/linnkit/runtime-kernel/events`。
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 文档入口
|
|
156
|
+
|
|
157
|
+
| 文档 | 内容 |
|
|
158
|
+
|---|---|
|
|
159
|
+
| [docs/integration/README.md](./docs/integration/README.md) | 接入总入口 |
|
|
160
|
+
| [docs/integration/01-installation.md](./docs/integration/01-installation.md) | 安装和包源配置 |
|
|
161
|
+
| [docs/integration/02-quickstart.md](./docs/integration/02-quickstart.md) | quickstart demo |
|
|
162
|
+
| [docs/integration/agent-registration-guide.md](./docs/integration/agent-registration-guide.md) | agent 注册与 `AgentSpec` |
|
|
163
|
+
| [docs/integration/context-engineering.md](./docs/integration/context-engineering.md) | 上下文策略、trace、tokenizer |
|
|
164
|
+
| [docs/integration/context-fences.md](./docs/integration/context-fences.md) | host 上下文注入 |
|
|
165
|
+
| [docs/integration/tools.md](./docs/integration/tools.md) | 工具接入总览 |
|
|
166
|
+
| [docs/integration/tool-development-guide.md](./docs/integration/tool-development-guide.md) | 工具开发细节 |
|
|
167
|
+
| [docs/integration/run-supervisor.md](./docs/integration/run-supervisor.md) | run 生命周期管理 |
|
|
168
|
+
| [docs/integration/testing.md](./docs/integration/testing.md) | testkit 和不变量 |
|
|
169
|
+
| [CHANGELOG.md](./CHANGELOG.md) | 公开版本更新记录 |
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 当前状态
|
|
174
|
+
|
|
175
|
+
- 当前版本:以 [package.json](./package.json) 为准。
|
|
176
|
+
- 当前发布:npmjs.com 公开发布。
|
|
177
|
+
- 稳定性:仍是 `0.x`,但公开子入口已经锁定;Context Engineering API 自 0.6.0 起基本稳定。
|
|
178
|
+
- 开源状态:已按 MIT 协议开源,源码仓为 <https://github.com/linnlabs/linnkit>。
|
|
179
|
+
|
|
180
|
+
## License
|
|
181
|
+
|
|
182
|
+
MIT — 见 [LICENSE](./LICENSE)。
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { A as AiMessage } from './messages-XthmnHZ3.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Agent runtime 最小调用协议。
|
|
5
|
+
*
|
|
6
|
+
* 中文备注:
|
|
7
|
+
* - 这里只声明 runtime-kernel / context-core 真正读取的字段;
|
|
8
|
+
* - 产品层的 AgentInvokeRequest 可以通过结构类型自然满足该接口;
|
|
9
|
+
* - agent package 不再从 app core 反向导入调用协议;
|
|
10
|
+
* - 公共合同面不依赖产品 enum:promptKey 在 ports 层是 opaque string。
|
|
11
|
+
*/
|
|
12
|
+
interface AgentInvocationRequest {
|
|
13
|
+
query: string;
|
|
14
|
+
promptKey: string;
|
|
15
|
+
model_id?: string;
|
|
16
|
+
imageGenerationModelId?: string;
|
|
17
|
+
/**
|
|
18
|
+
* 兼容字段。
|
|
19
|
+
*
|
|
20
|
+
* 当前仍允许 host 显式传入 `chat`,但长期目标不是维护两套并列核心模式;
|
|
21
|
+
* 纯聊天会逐步收敛为“不给工具的 agent 形态”。
|
|
22
|
+
*/
|
|
23
|
+
mode?: 'agent' | 'chat';
|
|
24
|
+
maxSteps?: number;
|
|
25
|
+
enableTools?: boolean;
|
|
26
|
+
availableTools?: string[];
|
|
27
|
+
conversationHistory?: AiMessage[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type { AgentInvocationRequest as A };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { A as AiMessage } from './messages-XthmnHZ3.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Agent runtime 最小调用协议。
|
|
5
|
+
*
|
|
6
|
+
* 中文备注:
|
|
7
|
+
* - 这里只声明 runtime-kernel / context-core 真正读取的字段;
|
|
8
|
+
* - 产品层的 AgentInvokeRequest 可以通过结构类型自然满足该接口;
|
|
9
|
+
* - agent package 不再从 app core 反向导入调用协议;
|
|
10
|
+
* - 公共合同面不依赖产品 enum:promptKey 在 ports 层是 opaque string。
|
|
11
|
+
*/
|
|
12
|
+
interface AgentInvocationRequest {
|
|
13
|
+
query: string;
|
|
14
|
+
promptKey: string;
|
|
15
|
+
model_id?: string;
|
|
16
|
+
imageGenerationModelId?: string;
|
|
17
|
+
/**
|
|
18
|
+
* 兼容字段。
|
|
19
|
+
*
|
|
20
|
+
* 当前仍允许 host 显式传入 `chat`,但长期目标不是维护两套并列核心模式;
|
|
21
|
+
* 纯聊天会逐步收敛为“不给工具的 agent 形态”。
|
|
22
|
+
*/
|
|
23
|
+
mode?: 'agent' | 'chat';
|
|
24
|
+
maxSteps?: number;
|
|
25
|
+
enableTools?: boolean;
|
|
26
|
+
availableTools?: string[];
|
|
27
|
+
conversationHistory?: AiMessage[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type { AgentInvocationRequest as A };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file runtime-kernel/events/agentEvents.ts
|
|
3
|
+
* @description graph 主执行链使用的最小 Agent 事件契约
|
|
4
|
+
*
|
|
5
|
+
* 中文备注:
|
|
6
|
+
* - 该文件只承载 runtime-kernel 主链路真正需要识别的事件子集;
|
|
7
|
+
* - 目标是让 `executor` / `llmNode` / `eventMappers` 不再反向依赖宿主或产品层事件定义;
|
|
8
|
+
* - host/product 层若有更丰富的事件,只要结构兼容,仍可在边界透传进来。
|
|
9
|
+
*/
|
|
10
|
+
interface AgentEvent {
|
|
11
|
+
type: string;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
id?: string;
|
|
14
|
+
/**
|
|
15
|
+
* 中文备注:
|
|
16
|
+
* - 该标记只在运行期内存中使用,用于避免同一事件被 SSE 重复分发;
|
|
17
|
+
* - 不属于持久化协议字段。
|
|
18
|
+
*/
|
|
19
|
+
__dispatched_via_sse__?: true;
|
|
20
|
+
}
|
|
21
|
+
interface BaseToolLifecycleAgentEvent extends AgentEvent {
|
|
22
|
+
tool_name: string;
|
|
23
|
+
tool_args: Record<string, unknown>;
|
|
24
|
+
tool_calls?: unknown[];
|
|
25
|
+
tool_call_id?: string;
|
|
26
|
+
phase?: 'start' | 'update' | 'complete' | 'error';
|
|
27
|
+
status?: 'loading' | 'success' | 'error';
|
|
28
|
+
payload?: Record<string, unknown>;
|
|
29
|
+
meta?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
interface ThoughtEvent extends AgentEvent {
|
|
32
|
+
type: 'thought';
|
|
33
|
+
content: string;
|
|
34
|
+
delta?: string;
|
|
35
|
+
is_complete?: boolean;
|
|
36
|
+
meta?: Record<string, unknown>;
|
|
37
|
+
thought_message_id?: string;
|
|
38
|
+
}
|
|
39
|
+
interface ToolCallDecisionEvent extends BaseToolLifecycleAgentEvent {
|
|
40
|
+
type: 'tool_call_decision';
|
|
41
|
+
}
|
|
42
|
+
interface ToolProcessEvent extends BaseToolLifecycleAgentEvent {
|
|
43
|
+
type: 'tool_process';
|
|
44
|
+
}
|
|
45
|
+
interface ObservationEvent extends AgentEvent {
|
|
46
|
+
type: 'observation';
|
|
47
|
+
tool_name: string;
|
|
48
|
+
tool_call_id?: string;
|
|
49
|
+
output: string;
|
|
50
|
+
success?: boolean;
|
|
51
|
+
payload?: Record<string, unknown>;
|
|
52
|
+
duration_ms?: number;
|
|
53
|
+
}
|
|
54
|
+
interface FinalAnswerEvent extends AgentEvent {
|
|
55
|
+
type: 'final_answer';
|
|
56
|
+
answer: string;
|
|
57
|
+
answer_id?: string;
|
|
58
|
+
answerId?: string;
|
|
59
|
+
reasoning_details?: unknown[];
|
|
60
|
+
meta?: Record<string, unknown>;
|
|
61
|
+
}
|
|
62
|
+
interface ErrorEvent extends AgentEvent {
|
|
63
|
+
type: 'error';
|
|
64
|
+
error: string;
|
|
65
|
+
details?: string;
|
|
66
|
+
}
|
|
67
|
+
interface StreamChunkEvent extends AgentEvent {
|
|
68
|
+
type: 'stream_chunk';
|
|
69
|
+
content: string;
|
|
70
|
+
answer_id?: string;
|
|
71
|
+
seq?: number;
|
|
72
|
+
is_last?: boolean;
|
|
73
|
+
isLast?: boolean;
|
|
74
|
+
}
|
|
75
|
+
interface ProviderSidecarEvent extends AgentEvent {
|
|
76
|
+
type: 'provider_sidecar';
|
|
77
|
+
reasoning_details?: unknown[];
|
|
78
|
+
}
|
|
79
|
+
type AnyAgentEvent = ThoughtEvent | ToolCallDecisionEvent | ToolProcessEvent | ObservationEvent | FinalAnswerEvent | ErrorEvent | StreamChunkEvent | ProviderSidecarEvent;
|
|
80
|
+
|
|
81
|
+
export type { AnyAgentEvent as A };
|