@tangleai/agents 0.21.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/CHANGELOG.md +30 -0
- package/LICENSE +21 -0
- package/README.md +854 -0
- package/package.json +85 -0
- package/src/agent.d.ts +160 -0
- package/src/agent.js +1021 -0
- package/src/index.d.ts +11 -0
- package/src/index.js +13 -0
- package/src/program-result.d.ts +111 -0
- package/src/program-result.js +48 -0
- package/src/program-session.d.ts +48 -0
- package/src/program-session.js +121 -0
- package/src/program-shape.d.ts +21 -0
- package/src/program-shape.js +53 -0
- package/src/program.d.ts +244 -0
- package/src/program.js +940 -0
- package/src/recursive.d.ts +148 -0
- package/src/recursive.js +384 -0
- package/src/refine.d.ts +58 -0
- package/src/refine.js +599 -0
- package/src/schemas/program.d.ts +82 -0
- package/src/schemas/program.js +205 -0
- package/src/toolbox.d.ts +55 -0
- package/src/toolbox.js +178 -0
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tangleai/agents",
|
|
3
|
+
"version": "0.21.1",
|
|
4
|
+
"description": "Validated tools, bounded agents, action programs, recursive execution and guarded refinement.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./src/index.js",
|
|
8
|
+
"types": "./src/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./src/index.d.ts",
|
|
12
|
+
"import": "./src/index.js",
|
|
13
|
+
"default": "./src/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./toolbox": {
|
|
16
|
+
"types": "./src/toolbox.d.ts",
|
|
17
|
+
"import": "./src/toolbox.js",
|
|
18
|
+
"default": "./src/toolbox.js"
|
|
19
|
+
},
|
|
20
|
+
"./agent": {
|
|
21
|
+
"types": "./src/agent.d.ts",
|
|
22
|
+
"import": "./src/agent.js",
|
|
23
|
+
"default": "./src/agent.js"
|
|
24
|
+
},
|
|
25
|
+
"./program": {
|
|
26
|
+
"types": "./src/program.d.ts",
|
|
27
|
+
"import": "./src/program.js",
|
|
28
|
+
"default": "./src/program.js"
|
|
29
|
+
},
|
|
30
|
+
"./recursive": {
|
|
31
|
+
"types": "./src/recursive.d.ts",
|
|
32
|
+
"import": "./src/recursive.js",
|
|
33
|
+
"default": "./src/recursive.js"
|
|
34
|
+
},
|
|
35
|
+
"./refine": {
|
|
36
|
+
"types": "./src/refine.d.ts",
|
|
37
|
+
"import": "./src/refine.js",
|
|
38
|
+
"default": "./src/refine.js"
|
|
39
|
+
},
|
|
40
|
+
"./schemas/program": {
|
|
41
|
+
"types": "./src/schemas/program.d.ts",
|
|
42
|
+
"import": "./src/schemas/program.js",
|
|
43
|
+
"default": "./src/schemas/program.js"
|
|
44
|
+
},
|
|
45
|
+
"./program-result": {
|
|
46
|
+
"types": "./src/program-result.d.ts",
|
|
47
|
+
"import": "./src/program-result.js",
|
|
48
|
+
"default": "./src/program-result.js"
|
|
49
|
+
},
|
|
50
|
+
"./program-session": {
|
|
51
|
+
"types": "./src/program-session.d.ts",
|
|
52
|
+
"import": "./src/program-session.js",
|
|
53
|
+
"default": "./src/program-session.js"
|
|
54
|
+
},
|
|
55
|
+
"./package.json": "./package.json"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=24"
|
|
59
|
+
},
|
|
60
|
+
"sideEffects": false,
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"@jarenjs/core": "0.84.3",
|
|
63
|
+
"@jarenjs/validate": "0.84.3",
|
|
64
|
+
"@tangleai/models": "^0.21.1",
|
|
65
|
+
"@tangleai/context": "^0.21.1",
|
|
66
|
+
"@jarenjs/contract": "0.84.3"
|
|
67
|
+
},
|
|
68
|
+
"private": false,
|
|
69
|
+
"files": [
|
|
70
|
+
"src/**/*.js",
|
|
71
|
+
"src/**/*.d.ts",
|
|
72
|
+
"README.md",
|
|
73
|
+
"LICENSE",
|
|
74
|
+
"CHANGELOG.md"
|
|
75
|
+
],
|
|
76
|
+
"publishConfig": {
|
|
77
|
+
"access": "public",
|
|
78
|
+
"registry": "https://registry.npmjs.org/"
|
|
79
|
+
},
|
|
80
|
+
"repository": {
|
|
81
|
+
"type": "git",
|
|
82
|
+
"url": "git+https://github.com/jklarenbeek/tangleai.git",
|
|
83
|
+
"directory": "packages/agents"
|
|
84
|
+
}
|
|
85
|
+
}
|
package/src/agent.d.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} AgentHooks
|
|
3
|
+
* @property {(text: string) => void} [onDelta] - streamed reply text
|
|
4
|
+
* @property {(text: string) => void} [onReasoning] - streamed thinking
|
|
5
|
+
* @property {(call: { name: string, arguments: string }) => void} [onToolCall]
|
|
6
|
+
* @property {(step: { name: string, result: any }) => void} [onToolResult]
|
|
7
|
+
* @property {AbortSignal} [signal]
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* @param {{ client: { complete: (request: any) => Promise<any> },
|
|
11
|
+
* toolbox?: { toFunctionTools: () => any[], execute: (name: string, args: any) => any } | null,
|
|
12
|
+
* system?: string, maxToolRounds?: number, maxToolResultChars?: number,
|
|
13
|
+
* historyBudget?: number, ledger?: any,
|
|
14
|
+
* budget?: { turns?: number, tokens?: number, ms?: number,
|
|
15
|
+
* spent?: { turns?: number, tokens?: number, ms?: number } },
|
|
16
|
+
* retrieval?: { memories?: { tags?: string[], where?: any, limit?: number },
|
|
17
|
+
* skills?: { tags?: string[], where?: any, limit?: number } },
|
|
18
|
+
* now?: () => number,
|
|
19
|
+
* environment?: any, transcript?: { slot?: string, window?: number },
|
|
20
|
+
* compaction?: (droppedRounds: any[][], addresses?: any[]) => string }} options
|
|
21
|
+
* - `historyBudget` caps the request history in CHARACTERS (tokens
|
|
22
|
+
* are provider-private; characters are deterministic). When a
|
|
23
|
+
* request would exceed it, the middle of the conversation is
|
|
24
|
+
* replaced by one synopsis message; the system prompt, the first
|
|
25
|
+
* user message and the largest tail that fits always survive, and
|
|
26
|
+
* cuts happen only at tool-round boundaries so `tool_calls`/`tool`
|
|
27
|
+
* pairing stays wire-legal. `compaction` replaces the built-in
|
|
28
|
+
* synopsis writer (it receives the dropped rounds, each an array of
|
|
29
|
+
* wire messages, and — with a ledger — the address of each). The
|
|
30
|
+
* returned transcript is always the FULL, uncompacted history.
|
|
31
|
+
* - `ledger` (anything with `putSlot`/`getSlot`/`readSlot`, normally
|
|
32
|
+
* `createLedger()`) makes compaction RECOVERABLE: each dropped round
|
|
33
|
+
* is archived to a content-addressed slot before the synopsis is
|
|
34
|
+
* written, every synopsis line carries its address, and a `recall`
|
|
35
|
+
* tool is registered so the model can fetch one back. Nothing leaves
|
|
36
|
+
* the request without a copy that can be named. With no ledger the
|
|
37
|
+
* original lossy path runs unchanged. A ledger also supplies the
|
|
38
|
+
* active goal composed into every request, and the memories and
|
|
39
|
+
* skills `retrieval` asks for.
|
|
40
|
+
* - `budget` is a hard stop, not a warning: `turns` (one turn is one
|
|
41
|
+
* MODEL CALL — the unit that costs money and the unit a resumed
|
|
42
|
+
* session keeps counting), `tokens` and `ms` each end the run with a
|
|
43
|
+
* named `stopReason` (`budget-turns`, `budget-tokens`, `budget-ms`)
|
|
44
|
+
* and a message saying what remains. Each is optional; `spent` seeds
|
|
45
|
+
* the counters so a budget survives a reload. The `ms` clock starts at
|
|
46
|
+
* the first model call and is wall-clock from there.
|
|
47
|
+
* - `retrieval` composes ledger memories and skills into the system
|
|
48
|
+
* prompt of every request, with the ledger's own `recall` query shape.
|
|
49
|
+
* Absent, nothing is retrieved — the goal is unconditional, but what
|
|
50
|
+
* else is worth carrying is the host's call.
|
|
51
|
+
* - `now` returns milliseconds (`Date.now` by default), injected so a
|
|
52
|
+
* time budget is testable.
|
|
53
|
+
* - `environment` (from `createEnvironment`) registers the corpus
|
|
54
|
+
* operations as tools — `env_digest`, `env_peek`, `env_grep`,
|
|
55
|
+
* `env_chunk`, `env_stat`, `env_read` — beside the host's, skipping any
|
|
56
|
+
* name the host already registered. Content never enters a request
|
|
57
|
+
* unasked: every one of them answers with metadata and addresses
|
|
58
|
+
* except `env_read`, which makes the model state a character budget.
|
|
59
|
+
* - `transcript` (needs `environment`) makes the CONVERSATION one of
|
|
60
|
+
* those slots: it is written whole before every call and the request
|
|
61
|
+
* keeps `window` round units plus the address of the rest. That is the
|
|
62
|
+
* alternative to `historyBudget` rather than a tuning of it — there is
|
|
63
|
+
* no budget to exceed when the history is addressed instead of resent.
|
|
64
|
+
* Both together is legal and redundant; neither changes the other's
|
|
65
|
+
* behaviour.
|
|
66
|
+
* @returns {{ send: (history: any[], hooks?: AgentHooks) => Promise<{
|
|
67
|
+
* message: any, messages: any[], steps: any[], stopReason: string }>,
|
|
68
|
+
* resume: (history?: any[], hooks?: AgentHooks) => Promise<{
|
|
69
|
+
* message: any, messages: any[], steps: any[], stopReason: string }>,
|
|
70
|
+
* spend: () => { turns: number, tokens: number, ms: number } }}
|
|
71
|
+
*/
|
|
72
|
+
export function createAgent(options: {
|
|
73
|
+
client: {
|
|
74
|
+
complete: (request: any) => Promise<any>;
|
|
75
|
+
};
|
|
76
|
+
toolbox?: {
|
|
77
|
+
toFunctionTools: () => any[];
|
|
78
|
+
execute: (name: string, args: any) => any;
|
|
79
|
+
} | null;
|
|
80
|
+
system?: string;
|
|
81
|
+
maxToolRounds?: number;
|
|
82
|
+
maxToolResultChars?: number;
|
|
83
|
+
historyBudget?: number;
|
|
84
|
+
ledger?: any;
|
|
85
|
+
budget?: {
|
|
86
|
+
turns?: number;
|
|
87
|
+
tokens?: number;
|
|
88
|
+
ms?: number;
|
|
89
|
+
spent?: {
|
|
90
|
+
turns?: number;
|
|
91
|
+
tokens?: number;
|
|
92
|
+
ms?: number;
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
retrieval?: {
|
|
96
|
+
memories?: {
|
|
97
|
+
tags?: string[];
|
|
98
|
+
where?: any;
|
|
99
|
+
limit?: number;
|
|
100
|
+
};
|
|
101
|
+
skills?: {
|
|
102
|
+
tags?: string[];
|
|
103
|
+
where?: any;
|
|
104
|
+
limit?: number;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
now?: () => number;
|
|
108
|
+
environment?: any;
|
|
109
|
+
transcript?: {
|
|
110
|
+
slot?: string;
|
|
111
|
+
window?: number;
|
|
112
|
+
};
|
|
113
|
+
compaction?: (droppedRounds: any[][], addresses?: any[]) => string;
|
|
114
|
+
}): {
|
|
115
|
+
send: (history: any[], hooks?: AgentHooks) => Promise<{
|
|
116
|
+
message: any;
|
|
117
|
+
messages: any[];
|
|
118
|
+
steps: any[];
|
|
119
|
+
stopReason: string;
|
|
120
|
+
}>;
|
|
121
|
+
resume: (history?: any[], hooks?: AgentHooks) => Promise<{
|
|
122
|
+
message: any;
|
|
123
|
+
messages: any[];
|
|
124
|
+
steps: any[];
|
|
125
|
+
stopReason: string;
|
|
126
|
+
}>;
|
|
127
|
+
spend: () => {
|
|
128
|
+
turns: number;
|
|
129
|
+
tokens: number;
|
|
130
|
+
ms: number;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* The conversation as text a `grep` can answer from: one header line per
|
|
135
|
+
* message, then its content. Line-oriented on purpose — `grep` reports
|
|
136
|
+
* the line that matched, so a tool result written as one JSON line comes
|
|
137
|
+
* back as one legible hit with its address beside it.
|
|
138
|
+
* @param {any[]} messages
|
|
139
|
+
* @returns {string}
|
|
140
|
+
*/
|
|
141
|
+
export function transcriptText(messages: any[]): string;
|
|
142
|
+
export type AgentHooks = {
|
|
143
|
+
/**
|
|
144
|
+
* - streamed reply text
|
|
145
|
+
*/
|
|
146
|
+
onDelta?: (text: string) => void;
|
|
147
|
+
/**
|
|
148
|
+
* - streamed thinking
|
|
149
|
+
*/
|
|
150
|
+
onReasoning?: (text: string) => void;
|
|
151
|
+
onToolCall?: (call: {
|
|
152
|
+
name: string;
|
|
153
|
+
arguments: string;
|
|
154
|
+
}) => void;
|
|
155
|
+
onToolResult?: (step: {
|
|
156
|
+
name: string;
|
|
157
|
+
result: any;
|
|
158
|
+
}) => void;
|
|
159
|
+
signal?: AbortSignal;
|
|
160
|
+
};
|