@tangle-network/agent-app 0.1.3 → 0.1.4
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/chunk-5RV6CAHZ.js +137 -0
- package/dist/chunk-5RV6CAHZ.js.map +1 -0
- package/dist/{chunk-7P6VIHI4.js → chunk-AQ2BOPOQ.js} +8 -2
- package/dist/{chunk-7P6VIHI4.js.map → chunk-AQ2BOPOQ.js.map} +1 -1
- package/dist/chunk-EEPJGZJW.js +102 -0
- package/dist/chunk-EEPJGZJW.js.map +1 -0
- package/dist/chunk-EZXN67KE.js +318 -0
- package/dist/chunk-EZXN67KE.js.map +1 -0
- package/dist/config/index.d.ts +367 -0
- package/dist/config/index.js +9 -0
- package/dist/config/index.js.map +1 -0
- package/dist/delegation/index.d.ts +16 -1
- package/dist/delegation/index.js +5 -3
- package/dist/index.d.ts +7 -2
- package/dist/index.js +39 -5
- package/dist/knowledge-loop/index.d.ts +208 -0
- package/dist/knowledge-loop/index.js +11 -0
- package/dist/knowledge-loop/index.js.map +1 -0
- package/dist/model-BOP69mVu.d.ts +35 -0
- package/dist/preset-cloudflare/index.d.ts +244 -0
- package/dist/preset-cloudflare/index.js +23 -0
- package/dist/preset-cloudflare/index.js.map +1 -0
- package/dist/runtime/index.d.ts +2 -35
- package/package.json +31 -5
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { KnowledgeResearchLoopContext, AddSourceTextInput, SourceAdapter, RunKnowledgeResearchLoopOptions, KnowledgeResearchLoopResult } from '@tangle-network/agent-knowledge';
|
|
2
|
+
import { KnowledgeSourceSpec, AgentKnowledgeConfig } from '../config/index.js';
|
|
3
|
+
import '../knowledge/index.js';
|
|
4
|
+
import '@tangle-network/agent-eval';
|
|
5
|
+
import '../model-BOP69mVu.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `@tangle-network/agent-app/knowledge-loop` — wire the declarative
|
|
9
|
+
* `AgentKnowledgeConfig` to a running, source-grounded, eval-gated knowledge
|
|
10
|
+
* acquisition loop.
|
|
11
|
+
*
|
|
12
|
+
* This module does NOT implement a loop. `@tangle-network/agent-knowledge`
|
|
13
|
+
* already ships `runKnowledgeResearchLoop` — the source-grounded,
|
|
14
|
+
* propose-don't-apply primitive (sources become immutable records first; only
|
|
15
|
+
* accepted `---FILE: knowledge/...---` write blocks are applied; lint +
|
|
16
|
+
* validation + optional readiness gate every iteration). It is pluggable on two
|
|
17
|
+
* seams: a `SourceAdapter[]` (how raw bytes/text become curated source records —
|
|
18
|
+
* text by default, audio/video/image adapters added by the consumer) and a
|
|
19
|
+
* `step` decider (the per-iteration policy: an agentic judge, a sandbox run, or
|
|
20
|
+
* a deterministic gate — the loop deliberately bakes none).
|
|
21
|
+
*
|
|
22
|
+
* `createKnowledgeLoop(config.knowledge, deps)` is the thin mapper between the
|
|
23
|
+
* two:
|
|
24
|
+
*
|
|
25
|
+
* - `config.knowledge.sources` → adapter selection. The text adapter is the
|
|
26
|
+
* default; `deps.adapters` is the multimodal seam (prepend an audio/video/
|
|
27
|
+
* image `SourceAdapter` and the loop ingests that media). agent-app bakes no
|
|
28
|
+
* media handler — it's a parameter.
|
|
29
|
+
* - `config.knowledge.loop` → `runKnowledgeResearchLoop` options. `goal` maps
|
|
30
|
+
* to the loop goal, `minConfidence` to the gate threshold, `freshness` is
|
|
31
|
+
* threaded to the decider so a per-source-freshness policy can read it.
|
|
32
|
+
* - `deps.decide` → the pluggable gate. DEFAULT is a reviewer policy
|
|
33
|
+
* (agent-knowledge's propose-don't-apply posture): a candidate carrying
|
|
34
|
+
* confidence below `minConfidence` is gated OUT (its proposal text is
|
|
35
|
+
* dropped — sources are still recorded, because grounding is never the thing
|
|
36
|
+
* we gate); at/above threshold it is accepted and the loop applies the write
|
|
37
|
+
* blocks. Swap in an agentic judge or a sandbox run by passing your own
|
|
38
|
+
* `decide`.
|
|
39
|
+
* - `deps.driver` → the agent-runtime turn driver (this repo's `../runtime`
|
|
40
|
+
* `runAppToolLoop` seam, or any compatible driver) the decider invokes for
|
|
41
|
+
* the loop's agent turns. Optional; a deterministic / sandbox decider needs
|
|
42
|
+
* no model turns and omits it.
|
|
43
|
+
*
|
|
44
|
+
* Layering: agent-knowledge and agent-runtime are PEER dependencies, never
|
|
45
|
+
* bundled. This module imports only TYPES + the loop entry from agent-knowledge
|
|
46
|
+
* and stays substrate-free behind the `decide` / `driver` / `adapters` seams.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A research candidate the decider evaluates before the loop applies it. This is
|
|
51
|
+
* the propose-don't-apply unit: notes + the sources discovered this iteration +
|
|
52
|
+
* the proposed write blocks, each carrying a confidence the gate scores against
|
|
53
|
+
* the configured `minConfidence`.
|
|
54
|
+
*/
|
|
55
|
+
interface KnowledgeCandidate {
|
|
56
|
+
/** Human-readable research transcript for this iteration. */
|
|
57
|
+
notes?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Textual source artifacts to register as immutable sources BEFORE any
|
|
60
|
+
* proposal is applied. Recording these is grounding, not the gated step — a
|
|
61
|
+
* rejected candidate still keeps its sources (so the next iteration is better
|
|
62
|
+
* grounded). The decider may not strip these.
|
|
63
|
+
*/
|
|
64
|
+
sourceTexts?: AddSourceTextInput[];
|
|
65
|
+
/** Local files to register as immutable sources (same grounding posture). */
|
|
66
|
+
sourcePaths?: string[];
|
|
67
|
+
/**
|
|
68
|
+
* Safe-write-protocol text (`---FILE: knowledge/...---` blocks). This IS the
|
|
69
|
+
* gated step: the default decider drops it when `confidence < minConfidence`.
|
|
70
|
+
*/
|
|
71
|
+
proposalText?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Aggregate confidence in this candidate's proposal, in [0, 1]. The default
|
|
74
|
+
* reviewer gate compares this to `minConfidence`. A candidate with no
|
|
75
|
+
* `proposalText` needs no confidence (nothing is gated).
|
|
76
|
+
*/
|
|
77
|
+
confidence?: number;
|
|
78
|
+
/** The researcher's signal that the goal is met; ends the loop. */
|
|
79
|
+
done?: boolean;
|
|
80
|
+
metadata?: Record<string, unknown>;
|
|
81
|
+
}
|
|
82
|
+
/** The verdict a gate returns for one candidate. */
|
|
83
|
+
interface KnowledgeGateVerdict {
|
|
84
|
+
/** Whether the candidate's proposal is accepted (applied) or gated out. */
|
|
85
|
+
accepted: boolean;
|
|
86
|
+
/** Why — surfaced in the decision metadata for audit. */
|
|
87
|
+
reason: string;
|
|
88
|
+
/** The confidence the gate scored (echoed for telemetry). */
|
|
89
|
+
confidence: number;
|
|
90
|
+
/** The threshold it was scored against. */
|
|
91
|
+
minConfidence: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The pluggable acquisition policy. Given the loop context (current index, lint,
|
|
95
|
+
* validation, freshness target, the driver), produce a candidate AND a gate
|
|
96
|
+
* verdict on it. This is the seam an agentic judge or a sandbox run plugs into;
|
|
97
|
+
* the default {@link createReviewerDecider} is a confidence gate.
|
|
98
|
+
*/
|
|
99
|
+
interface KnowledgeDecider {
|
|
100
|
+
(input: KnowledgeDeciderInput): Promise<KnowledgeDecision> | KnowledgeDecision;
|
|
101
|
+
}
|
|
102
|
+
interface KnowledgeDeciderInput {
|
|
103
|
+
/** The agent-knowledge loop context for this iteration. */
|
|
104
|
+
context: KnowledgeResearchLoopContext;
|
|
105
|
+
/** The acquisition goal (from `config.loop.goal` or a deps fallback). */
|
|
106
|
+
goal: string;
|
|
107
|
+
/** The confidence threshold a proposal must clear to be applied. */
|
|
108
|
+
minConfidence: number;
|
|
109
|
+
/** The freshness target (`config.loop.freshness`), if set. */
|
|
110
|
+
freshness?: string;
|
|
111
|
+
/** The configured sources, for a decider that fetches/selects among them. */
|
|
112
|
+
sources: KnowledgeSourceSpec[];
|
|
113
|
+
/** The agent-runtime turn driver, if one was supplied to the loop. */
|
|
114
|
+
driver?: KnowledgeLoopDriver;
|
|
115
|
+
}
|
|
116
|
+
interface KnowledgeDecision {
|
|
117
|
+
/** The candidate the policy produced (may be empty to end the loop). */
|
|
118
|
+
candidate: KnowledgeCandidate;
|
|
119
|
+
/** The gate's verdict on the candidate's proposal. */
|
|
120
|
+
verdict: KnowledgeGateVerdict;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The agent-runtime turn driver seam. This is exactly `../runtime`'s
|
|
124
|
+
* `runAppToolLoop` shape (a bounded, awaitable tool-driving turn loop over a
|
|
125
|
+
* model). Typed structurally so a decider can drive the loop's agent turns
|
|
126
|
+
* without this module importing the runtime engine. A deterministic / sandbox
|
|
127
|
+
* decider may omit it.
|
|
128
|
+
*/
|
|
129
|
+
interface KnowledgeLoopDriver {
|
|
130
|
+
(opts: {
|
|
131
|
+
systemPrompt: string;
|
|
132
|
+
userMessage: string;
|
|
133
|
+
}): Promise<{
|
|
134
|
+
finalText: string;
|
|
135
|
+
}>;
|
|
136
|
+
}
|
|
137
|
+
interface CreateKnowledgeLoopDeps {
|
|
138
|
+
/**
|
|
139
|
+
* The knowledge-base root the loop reads/writes (an agent-knowledge layout).
|
|
140
|
+
* Required — agent-knowledge owns disk; agent-app owns only the wiring.
|
|
141
|
+
*/
|
|
142
|
+
root: string;
|
|
143
|
+
/**
|
|
144
|
+
* The per-iteration policy. Defaults to {@link createReviewerDecider} keyed on
|
|
145
|
+
* the config's `minConfidence`. Pass your own to use an agentic judge or a
|
|
146
|
+
* sandbox run.
|
|
147
|
+
*/
|
|
148
|
+
decide?: KnowledgeDecider;
|
|
149
|
+
/**
|
|
150
|
+
* Extra source adapters (audio/video/image/PDF/...). The text adapter is
|
|
151
|
+
* always present as the fallback; these are tried first so a multimodal
|
|
152
|
+
* source is claimed by its adapter. This is the multimodal seam.
|
|
153
|
+
*/
|
|
154
|
+
adapters?: SourceAdapter[];
|
|
155
|
+
/** The agent-runtime turn driver for the loop's agent turns. */
|
|
156
|
+
driver?: KnowledgeLoopDriver;
|
|
157
|
+
/**
|
|
158
|
+
* Fallback goal when `config.loop.goal` is unset. agent-knowledge requires a
|
|
159
|
+
* goal; this keeps the loop runnable for a config with only requirement specs.
|
|
160
|
+
*/
|
|
161
|
+
defaultGoal?: string;
|
|
162
|
+
/** Default confidence threshold when `config.loop.minConfidence` is unset. */
|
|
163
|
+
defaultMinConfidence?: number;
|
|
164
|
+
/** Max research iterations (forwarded to agent-knowledge). Default 3. */
|
|
165
|
+
maxIterations?: number;
|
|
166
|
+
/** Actor stamped on the loop's knowledge events. */
|
|
167
|
+
actor?: string;
|
|
168
|
+
/** Abort the loop. */
|
|
169
|
+
signal?: AbortSignal;
|
|
170
|
+
/** Per-step hook (forwarded to agent-knowledge's `onStep`). */
|
|
171
|
+
onStep?: RunKnowledgeResearchLoopOptions['onStep'];
|
|
172
|
+
}
|
|
173
|
+
/** The handle `createKnowledgeLoop` returns. */
|
|
174
|
+
interface KnowledgeLoop {
|
|
175
|
+
/** Run the acquisition loop to completion and return the agent-knowledge result. */
|
|
176
|
+
run(): Promise<KnowledgeResearchLoopResult>;
|
|
177
|
+
/** The resolved goal the loop pursues. */
|
|
178
|
+
readonly goal: string;
|
|
179
|
+
/** The resolved confidence gate threshold. */
|
|
180
|
+
readonly minConfidence: number;
|
|
181
|
+
/** The adapters the loop uses (consumer extras first, text last). */
|
|
182
|
+
readonly adapters: SourceAdapter[];
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* The default gate — agent-knowledge's propose-don't-apply reviewer posture as a
|
|
186
|
+
* confidence threshold. A candidate's `proposalText` is applied only when its
|
|
187
|
+
* `confidence` is at/above `minConfidence`; otherwise the proposal is gated out
|
|
188
|
+
* (sources are still recorded). A candidate with no `proposalText` is trivially
|
|
189
|
+
* accepted (nothing to gate). This is the floor policy; swap in an agentic judge
|
|
190
|
+
* or a sandbox-run decider via `deps.decide` for richer review.
|
|
191
|
+
*/
|
|
192
|
+
declare function reviewCandidate(candidate: KnowledgeCandidate, minConfidence: number): KnowledgeGateVerdict;
|
|
193
|
+
/**
|
|
194
|
+
* Wrap a candidate-producing policy in the default reviewer gate. The policy
|
|
195
|
+
* decides WHAT to propose (notes, sources, proposalText, confidence); the gate
|
|
196
|
+
* decides whether the proposal is APPLIED. Use this when you have a proposer but
|
|
197
|
+
* want the standard confidence gate; pass a full {@link KnowledgeDecider} to
|
|
198
|
+
* `deps.decide` to own the gate too.
|
|
199
|
+
*/
|
|
200
|
+
declare function createReviewerDecider(propose: (input: KnowledgeDeciderInput) => Promise<KnowledgeCandidate> | KnowledgeCandidate): KnowledgeDecider;
|
|
201
|
+
/**
|
|
202
|
+
* Build a runnable knowledge-acquisition loop from the product's
|
|
203
|
+
* `AgentKnowledgeConfig` and a small set of seams. Maps config → agent-knowledge
|
|
204
|
+
* `runKnowledgeResearchLoop` options; never reimplements the loop.
|
|
205
|
+
*/
|
|
206
|
+
declare function createKnowledgeLoop(knowledge: AgentKnowledgeConfig, deps: CreateKnowledgeLoopDeps): KnowledgeLoop;
|
|
207
|
+
|
|
208
|
+
export { type CreateKnowledgeLoopDeps, type KnowledgeCandidate, type KnowledgeDecider, type KnowledgeDeciderInput, type KnowledgeDecision, type KnowledgeGateVerdict, type KnowledgeLoop, type KnowledgeLoopDriver, createKnowledgeLoop, createReviewerDecider, reviewCandidate };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the model config a Tangle agent's sandbox/runtime runs on.
|
|
3
|
+
*
|
|
4
|
+
* Every Tangle agent product resolves the SAME thing from env: the Tangle Router
|
|
5
|
+
* (OpenAI-compatible, metered at the platform markup against a single
|
|
6
|
+
* `TANGLE_API_KEY`) by default, with a direct-Anthropic BYOK escape hatch. The
|
|
7
|
+
* shape feeds the sandbox SDK's `backend.model`. Lifted here so no product
|
|
8
|
+
* hand-rolls the env parsing + the router default.
|
|
9
|
+
*/
|
|
10
|
+
interface TangleModelConfig {
|
|
11
|
+
/** The Tangle Router is OpenAI-compatible → driven via `openai-compat`.
|
|
12
|
+
* `anthropic` is the BYOK escape hatch. */
|
|
13
|
+
provider: 'openai-compat' | 'anthropic';
|
|
14
|
+
model: string;
|
|
15
|
+
apiKey: string;
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
}
|
|
18
|
+
interface ResolveModelOptions {
|
|
19
|
+
/** Env to read (defaults to process.env). */
|
|
20
|
+
env?: Record<string, string | undefined>;
|
|
21
|
+
/** Router base URL default when `TANGLE_ROUTER_BASE_URL` is unset. */
|
|
22
|
+
defaultRouterBaseUrl?: string;
|
|
23
|
+
}
|
|
24
|
+
declare const DEFAULT_TANGLE_ROUTER_BASE_URL = "https://router.tangle.tools/v1";
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the model config from env. DEFAULT path (`MODEL_PROVIDER` unset or
|
|
27
|
+
* `openai-compat`/`tangle-router`/`tcloud`): the Tangle Router, authenticated
|
|
28
|
+
* with `TANGLE_API_KEY`, model from `MODEL_NAME`. BYOK path
|
|
29
|
+
* (`MODEL_PROVIDER=anthropic`): direct Anthropic with `ANTHROPIC_API_KEY` +
|
|
30
|
+
* `ANTHROPIC_BASE_URL`. Throws (fail-loud) on a missing required var so a
|
|
31
|
+
* misconfigured deploy fails at boot, not mid-turn.
|
|
32
|
+
*/
|
|
33
|
+
declare function resolveTangleModelConfig(opts?: ResolveModelOptions): TangleModelConfig;
|
|
34
|
+
|
|
35
|
+
export { DEFAULT_TANGLE_ROUTER_BASE_URL as D, type ResolveModelOptions as R, type TangleModelConfig as T, resolveTangleModelConfig as r };
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { KeyProvisioner, KeyCrypto, WorkspaceKeyManager, WorkspaceKeyStore } from '../billing/index.js';
|
|
2
|
+
import { KnowledgeStateAccessor } from '../knowledge/index.js';
|
|
3
|
+
import { c as AppToolHandlers } from '../types-CeWor4bQ.js';
|
|
4
|
+
import { KvLike } from '../web/index.js';
|
|
5
|
+
import '@tangle-network/agent-eval';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `@tangle-network/agent-app/preset-cloudflare` — the batteries-included default
|
|
9
|
+
* stack.
|
|
10
|
+
*
|
|
11
|
+
* Every fleet agent runs the SAME backend: Cloudflare D1 (SQLite) through
|
|
12
|
+
* Drizzle for state, a KV namespace as the artifact vault, AES-GCM field crypto
|
|
13
|
+
* for PII, and per-workspace budget-capped model keys. The other agent-app
|
|
14
|
+
* modules are pure SEAMS — `./tools` needs an `AppToolHandlers`, `./knowledge`
|
|
15
|
+
* needs a `KnowledgeStateAccessor`, `./billing` needs a `WorkspaceKeyStore` +
|
|
16
|
+
* `KeyCrypto`. This module is the ONE implementation of those seams against the
|
|
17
|
+
* house stack, so a consumer that runs D1 + KV stands the whole shell up with
|
|
18
|
+
* config + bindings and ZERO handler code.
|
|
19
|
+
*
|
|
20
|
+
* Layering:
|
|
21
|
+
* - Drizzle is a PEER (the consumer installs `drizzle-orm`, never bundled). The
|
|
22
|
+
* schema is therefore expressed two ways that need no import here: the plain
|
|
23
|
+
* DDL ({@link PRESET_MIGRATION_SQL}) a consumer runs to create the tables, and
|
|
24
|
+
* a {@link createPresetDrizzleSchema} factory that takes the consumer's
|
|
25
|
+
* `drizzle-orm/sqlite-core` builder module and returns the typed tables. The
|
|
26
|
+
* column names in {@link PRESET_TABLES} are the contract the handlers,
|
|
27
|
+
* accessor, and DDL all agree on.
|
|
28
|
+
* - D1 + KV are STRUCTURAL: {@link D1Like} (Cloudflare `D1Database` satisfies it)
|
|
29
|
+
* and `KvLike` from `../web` (Cloudflare `KVNamespace` satisfies it). No
|
|
30
|
+
* `@cloudflare/workers-types` dependency.
|
|
31
|
+
* - Crypto/billing reuse `../crypto` + `../billing` exactly — this only wires
|
|
32
|
+
* them to the D1 key table.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/** A prepared, bound D1 statement. */
|
|
36
|
+
interface D1PreparedLike {
|
|
37
|
+
bind(...values: unknown[]): D1PreparedLike;
|
|
38
|
+
first<T = Record<string, unknown>>(colName?: string): Promise<T | null>;
|
|
39
|
+
run(): Promise<unknown>;
|
|
40
|
+
all<T = Record<string, unknown>>(): Promise<{
|
|
41
|
+
results: T[];
|
|
42
|
+
}>;
|
|
43
|
+
}
|
|
44
|
+
/** The D1 surface the preset needs. Cloudflare `D1Database` satisfies it. */
|
|
45
|
+
interface D1Like {
|
|
46
|
+
prepare(query: string): D1PreparedLike;
|
|
47
|
+
}
|
|
48
|
+
/** The preset table + column names — the contract the DDL, Drizzle schema,
|
|
49
|
+
* handlers, and accessor share. Exposed so a consumer can reference a column
|
|
50
|
+
* without a string literal. */
|
|
51
|
+
declare const PRESET_TABLES: {
|
|
52
|
+
readonly proposals: {
|
|
53
|
+
readonly name: "proposals";
|
|
54
|
+
readonly columns: {
|
|
55
|
+
readonly id: "id";
|
|
56
|
+
readonly workspaceId: "workspace_id";
|
|
57
|
+
readonly threadId: "thread_id";
|
|
58
|
+
readonly type: "type";
|
|
59
|
+
readonly title: "title";
|
|
60
|
+
readonly description: "description";
|
|
61
|
+
readonly status: "status";
|
|
62
|
+
readonly createdBy: "created_by";
|
|
63
|
+
readonly createdAt: "created_at";
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
readonly threads: {
|
|
67
|
+
readonly name: "threads";
|
|
68
|
+
readonly columns: {
|
|
69
|
+
readonly id: "id";
|
|
70
|
+
readonly workspaceId: "workspace_id";
|
|
71
|
+
readonly title: "title";
|
|
72
|
+
readonly createdAt: "created_at";
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
readonly knowledge: {
|
|
76
|
+
readonly name: "knowledge";
|
|
77
|
+
readonly columns: {
|
|
78
|
+
readonly id: "id";
|
|
79
|
+
readonly workspaceId: "workspace_id";
|
|
80
|
+
readonly path: "path";
|
|
81
|
+
readonly kind: "kind";
|
|
82
|
+
readonly label: "label";
|
|
83
|
+
readonly content: "content";
|
|
84
|
+
readonly createdAt: "created_at";
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
readonly deadlines: {
|
|
88
|
+
readonly name: "deadlines";
|
|
89
|
+
readonly columns: {
|
|
90
|
+
readonly id: "id";
|
|
91
|
+
readonly workspaceId: "workspace_id";
|
|
92
|
+
readonly threadId: "thread_id";
|
|
93
|
+
readonly title: "title";
|
|
94
|
+
readonly dueDate: "due_date";
|
|
95
|
+
readonly priority: "priority";
|
|
96
|
+
readonly status: "status";
|
|
97
|
+
readonly createdAt: "created_at";
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
readonly workspaceKeys: {
|
|
101
|
+
readonly name: "workspace_keys";
|
|
102
|
+
readonly columns: {
|
|
103
|
+
readonly id: "id";
|
|
104
|
+
readonly workspaceId: "workspace_id";
|
|
105
|
+
readonly keyId: "key_id";
|
|
106
|
+
readonly keyEncrypted: "key_encrypted";
|
|
107
|
+
readonly budgetUsd: "budget_usd";
|
|
108
|
+
readonly expiresAt: "expires_at";
|
|
109
|
+
readonly revokedAt: "revoked_at";
|
|
110
|
+
readonly createdAt: "created_at";
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Plain DDL for the preset schema — run by a consumer to create the tables with
|
|
116
|
+
* ZERO drizzle (`for (const sql of PRESET_MIGRATION_SQL) await db.prepare(sql).run()`,
|
|
117
|
+
* or paste into a `.sql` migration). One statement per table so D1's
|
|
118
|
+
* single-statement `prepare` accepts each. Matches {@link PRESET_TABLES} exactly.
|
|
119
|
+
*/
|
|
120
|
+
declare const PRESET_MIGRATION_SQL: readonly string[];
|
|
121
|
+
/** A chainable column builder — every modifier returns the builder so calls
|
|
122
|
+
* like `.notNull().default('pending')` typecheck. The concrete drizzle builders
|
|
123
|
+
* satisfy this structurally. */
|
|
124
|
+
interface DrizzleColumnLike {
|
|
125
|
+
primaryKey: () => DrizzleColumnLike;
|
|
126
|
+
notNull: () => DrizzleColumnLike;
|
|
127
|
+
default: (v: unknown) => DrizzleColumnLike;
|
|
128
|
+
}
|
|
129
|
+
/** The shape of a `drizzle-orm/sqlite-core` module — the few builders the
|
|
130
|
+
* preset schema uses. The consumer passes the real module; agent-app never
|
|
131
|
+
* imports it (it stays a peer). */
|
|
132
|
+
interface DrizzleSqliteCoreLike {
|
|
133
|
+
sqliteTable: (name: string, columns: Record<string, DrizzleColumnLike>) => unknown;
|
|
134
|
+
text: (name?: string) => DrizzleColumnLike;
|
|
135
|
+
integer: (name?: string, config?: unknown) => DrizzleColumnLike;
|
|
136
|
+
real: (name?: string) => DrizzleColumnLike;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Build the typed Drizzle schema for the preset, given the consumer's
|
|
140
|
+
* `drizzle-orm/sqlite-core` module. Returns one table object per
|
|
141
|
+
* {@link PRESET_TABLES} entry — pass to `drizzle(db, { schema })` for typed
|
|
142
|
+
* queries, or to drizzle-kit for migration generation. agent-app never imports
|
|
143
|
+
* drizzle; the builder module is the seam.
|
|
144
|
+
*
|
|
145
|
+
* ```ts
|
|
146
|
+
* import * as d from 'drizzle-orm/sqlite-core'
|
|
147
|
+
* const schema = createPresetDrizzleSchema(d)
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
declare function createPresetDrizzleSchema(d: DrizzleSqliteCoreLike): {
|
|
151
|
+
threads: unknown;
|
|
152
|
+
proposals: unknown;
|
|
153
|
+
knowledge: unknown;
|
|
154
|
+
deadlines: unknown;
|
|
155
|
+
workspaceKeys: unknown;
|
|
156
|
+
};
|
|
157
|
+
/** The KV-backed vault. `KvLike` (from `../web`) is the structural KV contract;
|
|
158
|
+
* Cloudflare `KVNamespace` satisfies it. Artifacts are stored under their path. */
|
|
159
|
+
type VaultKv = KvLike;
|
|
160
|
+
interface PresetToolHandlerOptions {
|
|
161
|
+
/** The D1 database (Cloudflare `D1Database` satisfies {@link D1Like}). */
|
|
162
|
+
db: D1Like;
|
|
163
|
+
/** The KV namespace used as the artifact vault. */
|
|
164
|
+
vault: VaultKv;
|
|
165
|
+
/** Id generator. Default `crypto.randomUUID`. Injectable for deterministic tests. */
|
|
166
|
+
newId?: () => string;
|
|
167
|
+
/** Clock (epoch ms). Default `Date.now`. Injectable for deterministic tests. */
|
|
168
|
+
now?: () => number;
|
|
169
|
+
/** Vault path prefix for `render_ui` artifacts. Default `'ui'`. */
|
|
170
|
+
uiPathPrefix?: string;
|
|
171
|
+
/** Vault path prefix for `add_citation` artifacts. Default `'citations'`. */
|
|
172
|
+
citationPathPrefix?: string;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* The default {@link AppToolHandlers} for the house stack:
|
|
176
|
+
* - `submit_proposal` → insert a `proposals` row (`status='pending'`), deduped
|
|
177
|
+
* on (workspace, title) so a retried turn doesn't double-queue.
|
|
178
|
+
* - `schedule_followup` → insert a `deadlines` row, deduped on (workspace, title, due_date).
|
|
179
|
+
* - `render_ui` → write the schema JSON as a `ui/<thread>/<slug>.json`
|
|
180
|
+
* vault artifact AND a `knowledge` row pointing at it.
|
|
181
|
+
* - `add_citation` → write the quote as a `citations/<slug>.json` artifact AND
|
|
182
|
+
* a `knowledge` row.
|
|
183
|
+
*
|
|
184
|
+
* Returns the EXACT persisted content from `render_ui` (per the seam contract) so
|
|
185
|
+
* a completion oracle sees real bytes. Pure seam wiring: a consumer that runs
|
|
186
|
+
* D1 + KV gets all four tools with no handler code.
|
|
187
|
+
*/
|
|
188
|
+
declare function createPresetToolHandlers(opts: PresetToolHandlerOptions): AppToolHandlers;
|
|
189
|
+
interface PresetKnowledgeAccessorOptions {
|
|
190
|
+
db: D1Like;
|
|
191
|
+
/** The active workspace — every `count` is scoped to it. */
|
|
192
|
+
workspaceId: string;
|
|
193
|
+
/** Workspace config the `satisfiedBy: { config }` rules read. A resolved
|
|
194
|
+
* object (dot-path lookup), or a function the accessor calls per path. */
|
|
195
|
+
config: Record<string, unknown> | ((path: string) => unknown);
|
|
196
|
+
/** The default workspace fk column a `count` rule scopes on when its rule
|
|
197
|
+
* omits `where`. Default `'workspace_id'` (the preset schema convention). */
|
|
198
|
+
defaultWhereColumn?: string;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* The {@link KnowledgeStateAccessor} over the preset D1 schema — the seam that
|
|
202
|
+
* lets the declarative `satisfiedBy` rules resolve with ZERO consumer code:
|
|
203
|
+
* - `config(path)` reads the supplied workspace config by dot-path.
|
|
204
|
+
* - `count({ table, where, statusIn })` runs `SELECT count(*)` scoped to the
|
|
205
|
+
* active workspace (the rule's `where` column, default `workspace_id`),
|
|
206
|
+
* optionally filtered to `statusIn` via a parameterized `IN (...)`.
|
|
207
|
+
*
|
|
208
|
+
* Identifiers (table/column) are validated against a safe pattern before
|
|
209
|
+
* interpolation — they originate from the product's own config, never model
|
|
210
|
+
* input, but we fail loud rather than build a malformed/injectable query.
|
|
211
|
+
*/
|
|
212
|
+
declare function createD1KnowledgeStateAccessor(opts: PresetKnowledgeAccessorOptions): KnowledgeStateAccessor;
|
|
213
|
+
/** Build the {@link KeyCrypto} the billing key store uses — AES-256-GCM field
|
|
214
|
+
* crypto bound to the product's 64-char-hex `ENCRYPTION_KEY` (or a resolver).
|
|
215
|
+
* This is the concrete impl behind the `../billing` `KeyCrypto` seam. */
|
|
216
|
+
declare function createPresetFieldCrypto(key: string | (() => string)): KeyCrypto;
|
|
217
|
+
/**
|
|
218
|
+
* The {@link WorkspaceKeyStore} over the preset `workspace_keys` table — the
|
|
219
|
+
* persistence seam the per-workspace key manager needs. "Active" = a row with a
|
|
220
|
+
* null `revoked_at`. Pure D1 wiring; no key minting (that's the provisioner).
|
|
221
|
+
*/
|
|
222
|
+
declare function createPresetWorkspaceKeyStore(db: D1Like): WorkspaceKeyStore;
|
|
223
|
+
interface PresetBillingOptions {
|
|
224
|
+
db: D1Like;
|
|
225
|
+
/** The key provisioner (`@tangle-network/tcloud`'s client satisfies it structurally). */
|
|
226
|
+
provisioner: KeyProvisioner;
|
|
227
|
+
/** Field-crypto key (64-char hex) or resolver — encrypts the minted key at rest. */
|
|
228
|
+
encryptionKey: string | (() => string);
|
|
229
|
+
/** Default monthly USD allowance when a call doesn't specify one. */
|
|
230
|
+
defaultBudgetUsd: number;
|
|
231
|
+
/** Injectable clock. */
|
|
232
|
+
now?: () => Date;
|
|
233
|
+
/** tcloud product the key is scoped to. Default `'router'`. */
|
|
234
|
+
product?: string;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Stand up the per-workspace budget-capped {@link WorkspaceKeyManager} on the
|
|
238
|
+
* house stack: the preset `workspace_keys` D1 store + AES-GCM field crypto +
|
|
239
|
+
* the consumer's tcloud provisioner. The mint/rotate/rollover/usage LOGIC lives
|
|
240
|
+
* in `../billing`; this only binds it to the preset table + crypto.
|
|
241
|
+
*/
|
|
242
|
+
declare function createPresetWorkspaceKeyManager(opts: PresetBillingOptions): WorkspaceKeyManager;
|
|
243
|
+
|
|
244
|
+
export { type D1Like, type D1PreparedLike, type DrizzleColumnLike, type DrizzleSqliteCoreLike, PRESET_MIGRATION_SQL, PRESET_TABLES, type PresetBillingOptions, type PresetKnowledgeAccessorOptions, type PresetToolHandlerOptions, type VaultKv, createD1KnowledgeStateAccessor, createPresetDrizzleSchema, createPresetFieldCrypto, createPresetToolHandlers, createPresetWorkspaceKeyManager, createPresetWorkspaceKeyStore };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PRESET_MIGRATION_SQL,
|
|
3
|
+
PRESET_TABLES,
|
|
4
|
+
createD1KnowledgeStateAccessor,
|
|
5
|
+
createPresetDrizzleSchema,
|
|
6
|
+
createPresetFieldCrypto,
|
|
7
|
+
createPresetToolHandlers,
|
|
8
|
+
createPresetWorkspaceKeyManager,
|
|
9
|
+
createPresetWorkspaceKeyStore
|
|
10
|
+
} from "../chunk-EZXN67KE.js";
|
|
11
|
+
import "../chunk-EAJSWUU5.js";
|
|
12
|
+
import "../chunk-ZJGY7OMZ.js";
|
|
13
|
+
export {
|
|
14
|
+
PRESET_MIGRATION_SQL,
|
|
15
|
+
PRESET_TABLES,
|
|
16
|
+
createD1KnowledgeStateAccessor,
|
|
17
|
+
createPresetDrizzleSchema,
|
|
18
|
+
createPresetFieldCrypto,
|
|
19
|
+
createPresetToolHandlers,
|
|
20
|
+
createPresetWorkspaceKeyManager,
|
|
21
|
+
createPresetWorkspaceKeyStore
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,39 +1,6 @@
|
|
|
1
|
+
export { D as DEFAULT_TANGLE_ROUTER_BASE_URL, R as ResolveModelOptions, T as TangleModelConfig, r as resolveTangleModelConfig } from '../model-BOP69mVu.js';
|
|
1
2
|
import { d as AppToolOutcome } from '../types-CeWor4bQ.js';
|
|
2
3
|
|
|
3
|
-
/**
|
|
4
|
-
* Resolve the model config a Tangle agent's sandbox/runtime runs on.
|
|
5
|
-
*
|
|
6
|
-
* Every Tangle agent product resolves the SAME thing from env: the Tangle Router
|
|
7
|
-
* (OpenAI-compatible, metered at the platform markup against a single
|
|
8
|
-
* `TANGLE_API_KEY`) by default, with a direct-Anthropic BYOK escape hatch. The
|
|
9
|
-
* shape feeds the sandbox SDK's `backend.model`. Lifted here so no product
|
|
10
|
-
* hand-rolls the env parsing + the router default.
|
|
11
|
-
*/
|
|
12
|
-
interface TangleModelConfig {
|
|
13
|
-
/** The Tangle Router is OpenAI-compatible → driven via `openai-compat`.
|
|
14
|
-
* `anthropic` is the BYOK escape hatch. */
|
|
15
|
-
provider: 'openai-compat' | 'anthropic';
|
|
16
|
-
model: string;
|
|
17
|
-
apiKey: string;
|
|
18
|
-
baseUrl: string;
|
|
19
|
-
}
|
|
20
|
-
interface ResolveModelOptions {
|
|
21
|
-
/** Env to read (defaults to process.env). */
|
|
22
|
-
env?: Record<string, string | undefined>;
|
|
23
|
-
/** Router base URL default when `TANGLE_ROUTER_BASE_URL` is unset. */
|
|
24
|
-
defaultRouterBaseUrl?: string;
|
|
25
|
-
}
|
|
26
|
-
declare const DEFAULT_TANGLE_ROUTER_BASE_URL = "https://router.tangle.tools/v1";
|
|
27
|
-
/**
|
|
28
|
-
* Resolve the model config from env. DEFAULT path (`MODEL_PROVIDER` unset or
|
|
29
|
-
* `openai-compat`/`tangle-router`/`tcloud`): the Tangle Router, authenticated
|
|
30
|
-
* with `TANGLE_API_KEY`, model from `MODEL_NAME`. BYOK path
|
|
31
|
-
* (`MODEL_PROVIDER=anthropic`): direct Anthropic with `ANTHROPIC_API_KEY` +
|
|
32
|
-
* `ANTHROPIC_BASE_URL`. Throws (fail-loud) on a missing required var so a
|
|
33
|
-
* misconfigured deploy fails at boot, not mid-turn.
|
|
34
|
-
*/
|
|
35
|
-
declare function resolveTangleModelConfig(opts?: ResolveModelOptions): TangleModelConfig;
|
|
36
|
-
|
|
37
4
|
/**
|
|
38
5
|
* OpenAI-compatible stream → `LoopEvent` adapter, for NON-sandbox copilots.
|
|
39
6
|
*
|
|
@@ -216,4 +183,4 @@ interface StreamAppToolLoopOptions<Raw> {
|
|
|
216
183
|
*/
|
|
217
184
|
declare function streamAppToolLoop<Raw>(opts: StreamAppToolLoopOptions<Raw>): AsyncGenerator<StreamLoopYield<Raw>, void, unknown>;
|
|
218
185
|
|
|
219
|
-
export { type AppToolLoopOptions,
|
|
186
|
+
export { type AppToolLoopOptions, type LoopEvent, type LoopToolCall, type OpenAICompatStreamTurnOptions, type OpenAIStreamChunk, type StreamAppToolLoopOptions, type StreamLoopYield, type ToolLoopResult, createOpenAICompatStreamTurn, runAppToolLoop, streamAppToolLoop, toLoopEvents };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"packageManager": "pnpm@10.33.4",
|
|
5
5
|
"description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
|
|
6
6
|
"keywords": [
|
|
@@ -66,6 +66,21 @@
|
|
|
66
66
|
"import": "./dist/knowledge/index.js",
|
|
67
67
|
"default": "./dist/knowledge/index.js"
|
|
68
68
|
},
|
|
69
|
+
"./config": {
|
|
70
|
+
"types": "./dist/config/index.d.ts",
|
|
71
|
+
"import": "./dist/config/index.js",
|
|
72
|
+
"default": "./dist/config/index.js"
|
|
73
|
+
},
|
|
74
|
+
"./knowledge-loop": {
|
|
75
|
+
"types": "./dist/knowledge-loop/index.d.ts",
|
|
76
|
+
"import": "./dist/knowledge-loop/index.js",
|
|
77
|
+
"default": "./dist/knowledge-loop/index.js"
|
|
78
|
+
},
|
|
79
|
+
"./preset-cloudflare": {
|
|
80
|
+
"types": "./dist/preset-cloudflare/index.d.ts",
|
|
81
|
+
"import": "./dist/preset-cloudflare/index.js",
|
|
82
|
+
"default": "./dist/preset-cloudflare/index.js"
|
|
83
|
+
},
|
|
69
84
|
"./billing": {
|
|
70
85
|
"types": "./dist/billing/index.d.ts",
|
|
71
86
|
"import": "./dist/billing/index.js",
|
|
@@ -106,15 +121,26 @@
|
|
|
106
121
|
"typecheck": "tsc --noEmit"
|
|
107
122
|
},
|
|
108
123
|
"devDependencies": {
|
|
124
|
+
"@tangle-network/agent-eval": "^0.70.0",
|
|
125
|
+
"@tangle-network/agent-integrations": "^0.32.0",
|
|
126
|
+
"@tangle-network/agent-knowledge": "^1.5.2",
|
|
109
127
|
"@types/node": "^25.6.0",
|
|
110
128
|
"tsup": "^8.0.0",
|
|
111
129
|
"typescript": "^5.7.0",
|
|
112
|
-
"vitest": "^3.0.0"
|
|
113
|
-
"@tangle-network/agent-integrations": "^0.32.0",
|
|
114
|
-
"@tangle-network/agent-eval": "^0.70.0"
|
|
130
|
+
"vitest": "^3.0.0"
|
|
115
131
|
},
|
|
116
132
|
"peerDependencies": {
|
|
133
|
+
"@tangle-network/agent-eval": ">=0.50.0",
|
|
117
134
|
"@tangle-network/agent-integrations": ">=0.32.0",
|
|
118
|
-
"@tangle-network/agent-
|
|
135
|
+
"@tangle-network/agent-knowledge": ">=1.5.0",
|
|
136
|
+
"@tangle-network/agent-runtime": ">=0.21.0"
|
|
137
|
+
},
|
|
138
|
+
"peerDependenciesMeta": {
|
|
139
|
+
"@tangle-network/agent-knowledge": {
|
|
140
|
+
"optional": true
|
|
141
|
+
},
|
|
142
|
+
"@tangle-network/agent-runtime": {
|
|
143
|
+
"optional": true
|
|
144
|
+
}
|
|
119
145
|
}
|
|
120
146
|
}
|