loopengine 0.0.18 → 0.0.21
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/PROTOCOL.md +245 -0
- package/README.md +44 -5
- package/core/system-skills/composio-large-outputs/SKILL.md +25 -0
- package/dist/{cli.d.ts → bin/cli.d.ts} +25 -4
- package/dist/{cli.js → bin/cli.js} +131 -16
- package/dist/{agent-as-tool.d.ts → core/agent-as-tool.d.ts} +2 -2
- package/dist/{agent-as-tool.js → core/agent-as-tool.js} +1 -1
- package/dist/core/client.d.ts +113 -0
- package/dist/core/client.js +123 -0
- package/dist/core/discover-agents.d.ts +45 -0
- package/dist/{discover-agents.js → core/discover-agents.js} +11 -3
- package/dist/{gateway-tools.d.ts → core/gateway-tools.d.ts} +38 -6
- package/dist/{gateway-tools.js → core/gateway-tools.js} +140 -28
- package/dist/core/loop-events.d.ts +175 -0
- package/dist/core/loop-events.js +1 -0
- package/dist/{model-calls → core/model-calls}/anthropic-model-call.d.ts +1 -1
- package/dist/{model-calls → core/model-calls}/deepseek-model-call.d.ts +1 -1
- package/dist/{model-calls → core/model-calls}/openai-model-call.d.ts +1 -1
- package/dist/{model-calls → core/model-calls}/openai-model-call.js +1 -1
- package/dist/{run-agent.d.ts → core/run-agent.d.ts} +79 -11
- package/dist/{run-agent.js → core/run-agent.js} +242 -60
- package/dist/{session-store.d.ts → core/session-store.d.ts} +14 -2
- package/dist/{session-store.js → core/session-store.js} +19 -0
- package/dist/core/system-tools/ask_user.d.ts +72 -0
- package/dist/core/system-tools/ask_user.js +136 -0
- package/dist/core/system-tools/index.d.ts +3 -0
- package/dist/core/system-tools/index.js +12 -0
- package/dist/core/system-tools/read_file.d.ts +28 -0
- package/dist/core/system-tools/read_file.js +64 -0
- package/dist/{vector-index.js → core/vector-index.js} +1 -1
- package/dist/index.d.ts +19 -16
- package/dist/index.js +16 -9
- package/package.json +34 -28
- package/protocol/loop-event.schema.json +257 -0
- package/dist/discover-agents.d.ts +0 -24
- /package/dist/{agent-config.d.ts → core/agent-config.d.ts} +0 -0
- /package/dist/{agent-config.js → core/agent-config.js} +0 -0
- /package/dist/{model-calls → core/model-calls}/anthropic-model-call.js +0 -0
- /package/dist/{model-calls → core/model-calls}/deepseek-model-call.js +0 -0
- /package/dist/{vector-index.d.ts → core/vector-index.d.ts} +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://loopengine.co/protocol/loop-event.schema.json",
|
|
4
|
+
"title": "LoopEvent",
|
|
5
|
+
"description": "The full wire vocabulary of a loopengine turn — mirrors core/loop-events.ts exactly. One object per event; `type` is both the JSON discriminant and, on the SSE transport, the literal `event:` field name. See /PROTOCOL.md for transport bindings and stability guarantees.",
|
|
6
|
+
"oneOf": [
|
|
7
|
+
{ "$ref": "#/$defs/budgetCheck" },
|
|
8
|
+
{ "$ref": "#/$defs/promptCompaction" },
|
|
9
|
+
{ "$ref": "#/$defs/assistantText" },
|
|
10
|
+
{ "$ref": "#/$defs/actauthDecision" },
|
|
11
|
+
{ "$ref": "#/$defs/toolStarted" },
|
|
12
|
+
{ "$ref": "#/$defs/toolResult" },
|
|
13
|
+
{ "$ref": "#/$defs/toollaneResult" },
|
|
14
|
+
{ "$ref": "#/$defs/skillLoad" },
|
|
15
|
+
{ "$ref": "#/$defs/loopSkipped" },
|
|
16
|
+
{ "$ref": "#/$defs/loopMaxTurns" },
|
|
17
|
+
{ "$ref": "#/$defs/loopDenied" },
|
|
18
|
+
{ "$ref": "#/$defs/loopDone" },
|
|
19
|
+
{ "$ref": "#/$defs/session" },
|
|
20
|
+
{ "$ref": "#/$defs/approvalPending" },
|
|
21
|
+
{ "$ref": "#/$defs/questionPending" },
|
|
22
|
+
{ "$ref": "#/$defs/done" },
|
|
23
|
+
{ "$ref": "#/$defs/error" }
|
|
24
|
+
],
|
|
25
|
+
"$defs": {
|
|
26
|
+
"scope": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"description": "ActAuth's own Scope — which rules apply.",
|
|
29
|
+
"required": ["tenant", "environment", "agent"],
|
|
30
|
+
"properties": {
|
|
31
|
+
"tenant": { "type": "string" },
|
|
32
|
+
"environment": { "type": "string" },
|
|
33
|
+
"agent": { "type": "string" }
|
|
34
|
+
},
|
|
35
|
+
"additionalProperties": false
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
"budgetCheck": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"description": "Engine. Read-only context-budget check, run once per model call.",
|
|
41
|
+
"required": ["type", "action", "usedTokens", "budgetTokens", "ratio"],
|
|
42
|
+
"properties": {
|
|
43
|
+
"type": { "const": "budget:check" },
|
|
44
|
+
"action": { "enum": ["ok", "nudge", "over_hard_limit"] },
|
|
45
|
+
"usedTokens": { "type": "number" },
|
|
46
|
+
"budgetTokens": { "type": "number" },
|
|
47
|
+
"ratio": { "type": "number" },
|
|
48
|
+
"nudge": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"description": "Present only when action is 'nudge'.",
|
|
51
|
+
"required": ["role", "content"],
|
|
52
|
+
"properties": { "role": { "type": "string" }, "content": { "type": "string" } }
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"additionalProperties": false
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
"promptCompaction": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"description": "Engine. The prompt was rejected as too long, so compaction.ts's own recovery kicked in. from/to are message-array lengths, not token counts. The only recovery type with a dedicated event today — recovery.ts's other two failure modes (media-too-large, truncated output) have no hook wired up in run-agent.ts yet, so neither can currently fire.",
|
|
61
|
+
"required": ["type", "from", "to"],
|
|
62
|
+
"properties": {
|
|
63
|
+
"type": { "const": "prompt:compaction" },
|
|
64
|
+
"from": { "type": "number" },
|
|
65
|
+
"to": { "type": "number" }
|
|
66
|
+
},
|
|
67
|
+
"additionalProperties": false
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
"assistantText": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"description": "Engine. The model's own preamble alongside a tool_use request — the only live glimpse of assistant text before the turn's final answer.",
|
|
73
|
+
"required": ["type", "text"],
|
|
74
|
+
"properties": {
|
|
75
|
+
"type": { "const": "assistant:text" },
|
|
76
|
+
"text": { "type": "string" }
|
|
77
|
+
},
|
|
78
|
+
"additionalProperties": false
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
"actauthDecision": {
|
|
82
|
+
"type": "object",
|
|
83
|
+
"description": "Engine. One ActAuth Gate.evaluate() outcome per requested tool call. decision:'allow' can still mean a human was asked and said yes — see approval:pending for the live ask itself.",
|
|
84
|
+
"required": ["type", "tool", "decision", "reason"],
|
|
85
|
+
"properties": {
|
|
86
|
+
"type": { "const": "actauth:decision" },
|
|
87
|
+
"tool": { "type": "string" },
|
|
88
|
+
"decision": { "enum": ["allow", "ask", "deny"] },
|
|
89
|
+
"reason": { "type": "string" }
|
|
90
|
+
},
|
|
91
|
+
"additionalProperties": false
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
"toolStarted": {
|
|
95
|
+
"type": "object",
|
|
96
|
+
"description": "Engine. Fired the instant a call is decided, before it runs. Matched to its later tool:result by id.",
|
|
97
|
+
"required": ["type", "id", "tool", "args", "detailText"],
|
|
98
|
+
"properties": {
|
|
99
|
+
"type": { "const": "tool:started" },
|
|
100
|
+
"id": { "type": "string" },
|
|
101
|
+
"tool": { "type": "string" },
|
|
102
|
+
"args": { "type": "object" },
|
|
103
|
+
"detailText": { "type": "string" }
|
|
104
|
+
},
|
|
105
|
+
"additionalProperties": false
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
"toolResult": {
|
|
109
|
+
"type": "object",
|
|
110
|
+
"description": "Engine. A tool call's resolution — auto-allowed, interactively approved, denied, or skipped alike. args/detailText are omitted on some denied/skipped paths.",
|
|
111
|
+
"required": ["type", "id", "tool", "statusText"],
|
|
112
|
+
"properties": {
|
|
113
|
+
"type": { "const": "tool:result" },
|
|
114
|
+
"id": { "type": "string" },
|
|
115
|
+
"tool": { "type": "string" },
|
|
116
|
+
"args": { "type": "object" },
|
|
117
|
+
"detailText": { "type": "string" },
|
|
118
|
+
"statusText": { "type": "string" }
|
|
119
|
+
},
|
|
120
|
+
"additionalProperties": false
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
"toollaneResult": {
|
|
124
|
+
"type": "object",
|
|
125
|
+
"description": "Engine. ToolLane's own raw fulfil/reject outcome, logged alongside (not instead of) tool:result.",
|
|
126
|
+
"required": ["type", "name", "summary"],
|
|
127
|
+
"properties": {
|
|
128
|
+
"type": { "const": "toollane:result" },
|
|
129
|
+
"name": { "type": "string" },
|
|
130
|
+
"summary": { "type": "string" }
|
|
131
|
+
},
|
|
132
|
+
"additionalProperties": false
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
"skillLoad": {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"description": "Engine. A Skill tool_use block was resolved to a real skill body via SkillGarden's own lazy load. Not gated by ActAuth — Skill invocation isn't a real tool call.",
|
|
138
|
+
"required": ["type", "skill"],
|
|
139
|
+
"properties": {
|
|
140
|
+
"type": { "const": "skill:loaded" },
|
|
141
|
+
"skill": { "type": "string" }
|
|
142
|
+
},
|
|
143
|
+
"additionalProperties": false
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
"loopSkipped": {
|
|
147
|
+
"type": "object",
|
|
148
|
+
"description": "Engine. An approved call never ran because a sibling call in the same batch was denied — the whole batch cancels together.",
|
|
149
|
+
"required": ["type", "name", "deniedTools"],
|
|
150
|
+
"properties": {
|
|
151
|
+
"type": { "const": "loop:skipped" },
|
|
152
|
+
"name": { "type": "string" },
|
|
153
|
+
"deniedTools": { "type": "array", "items": { "type": "string" } }
|
|
154
|
+
},
|
|
155
|
+
"additionalProperties": false
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
"loopMaxTurns": {
|
|
159
|
+
"type": "object",
|
|
160
|
+
"description": "Engine. Hit config.maxTurns without the model producing a final answer. Terminal for the turn — see 'done'.",
|
|
161
|
+
"required": ["type", "maxTurns"],
|
|
162
|
+
"properties": {
|
|
163
|
+
"type": { "const": "loop:max_turns" },
|
|
164
|
+
"maxTurns": { "type": "number" }
|
|
165
|
+
},
|
|
166
|
+
"additionalProperties": false
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
"loopDenied": {
|
|
170
|
+
"type": "object",
|
|
171
|
+
"description": "Engine. A human denied at least one requested tool call this turn — the whole turn stops right there. Terminal for the turn — see 'done'.",
|
|
172
|
+
"required": ["type", "deniedTools"],
|
|
173
|
+
"properties": {
|
|
174
|
+
"type": { "const": "loop:denied" },
|
|
175
|
+
"deniedTools": { "type": "array", "items": { "type": "string" } }
|
|
176
|
+
},
|
|
177
|
+
"additionalProperties": false
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
"loopDone": {
|
|
181
|
+
"type": "object",
|
|
182
|
+
"description": "Engine. A genuine finish — the model produced text with no more tool_use blocks. Terminal for the turn — see 'done'.",
|
|
183
|
+
"required": ["type", "text"],
|
|
184
|
+
"properties": {
|
|
185
|
+
"type": { "const": "loop:done" },
|
|
186
|
+
"text": { "type": "string" }
|
|
187
|
+
},
|
|
188
|
+
"additionalProperties": false
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
"session": {
|
|
192
|
+
"type": "object",
|
|
193
|
+
"description": "Adapter. First event of every streamed turn — echoes back which session id this turn used.",
|
|
194
|
+
"required": ["type", "sessionId"],
|
|
195
|
+
"properties": {
|
|
196
|
+
"type": { "const": "session" },
|
|
197
|
+
"sessionId": { "type": "string" }
|
|
198
|
+
},
|
|
199
|
+
"additionalProperties": false
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
"approvalPending": {
|
|
203
|
+
"type": "object",
|
|
204
|
+
"description": "Adapter. A tool call needs a live human 'ask' decision. Resolve via POST /approvals/:id/approve or /deny.",
|
|
205
|
+
"required": ["type", "id", "tool", "args", "scope", "reason", "requestedAt"],
|
|
206
|
+
"properties": {
|
|
207
|
+
"type": { "const": "approval:pending" },
|
|
208
|
+
"id": { "type": "string" },
|
|
209
|
+
"tool": { "type": "string" },
|
|
210
|
+
"args": { "type": "object" },
|
|
211
|
+
"scope": { "$ref": "#/$defs/scope" },
|
|
212
|
+
"reason": { "type": "string" },
|
|
213
|
+
"requestedAt": { "type": "string", "format": "date-time" }
|
|
214
|
+
},
|
|
215
|
+
"additionalProperties": false
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
"questionPending": {
|
|
219
|
+
"type": "object",
|
|
220
|
+
"description": "Adapter. The system ask_user tool raised a genuinely ambiguous question. Resolve via POST /questions/:id/answer.",
|
|
221
|
+
"required": ["type", "id", "question", "agent", "requestedAt"],
|
|
222
|
+
"properties": {
|
|
223
|
+
"type": { "const": "question:pending" },
|
|
224
|
+
"id": { "type": "string" },
|
|
225
|
+
"question": { "type": "string" },
|
|
226
|
+
"options": { "type": "array", "items": { "type": "string" } },
|
|
227
|
+
"agent": { "type": "string" },
|
|
228
|
+
"sessionId": { "type": "string" },
|
|
229
|
+
"requestedAt": { "type": "string", "format": "date-time" }
|
|
230
|
+
},
|
|
231
|
+
"additionalProperties": false
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
"done": {
|
|
235
|
+
"type": "object",
|
|
236
|
+
"description": "Adapter. The turn is over — covers loop:done, loop:max_turns, and loop:denied alike. The one event every consumer can treat as 'nothing more is coming'.",
|
|
237
|
+
"required": ["type", "text"],
|
|
238
|
+
"properties": {
|
|
239
|
+
"type": { "const": "done" },
|
|
240
|
+
"text": { "type": "string" },
|
|
241
|
+
"stopReason": { "enum": ["max_turns", "denied"] }
|
|
242
|
+
},
|
|
243
|
+
"additionalProperties": false
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
"error": {
|
|
247
|
+
"type": "object",
|
|
248
|
+
"description": "Adapter. Something failed after the response was already committed — surfaced in-band since it's too late for an HTTP status code.",
|
|
249
|
+
"required": ["type", "error"],
|
|
250
|
+
"properties": {
|
|
251
|
+
"type": { "const": "error" },
|
|
252
|
+
"error": { "type": "string" }
|
|
253
|
+
},
|
|
254
|
+
"additionalProperties": false
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { AgentConfig } from '#agent-config.js';
|
|
2
|
-
import type { ModelCall } from '#run-agent.js';
|
|
3
|
-
export interface AgentModule {
|
|
4
|
-
config: AgentConfig;
|
|
5
|
-
/** Factory, not a shared instance — a fresh ModelCall per request/session. */
|
|
6
|
-
createModelCall: () => ModelCall;
|
|
7
|
-
}
|
|
8
|
-
/** Imports one agent module at `path` and resolves it to an AgentModule —
|
|
9
|
-
* the single-file version of what discoverAgents does over a whole
|
|
10
|
-
* directory, factored out so run-agent.ts's subagent loader (see
|
|
11
|
-
* agent-as-tool.ts / loadSubagentAsTools) can load one `subagents/<name>/
|
|
12
|
-
* index.ts` at a time without duplicating this resolution logic.
|
|
13
|
-
* `label` is only used in error messages — discoverAgents passes
|
|
14
|
-
* `'<file> in <dir>'`, callers loading a single known path can just pass
|
|
15
|
-
* that path. */
|
|
16
|
-
export declare function loadAgentModule(path: string, label: string): Promise<AgentModule>;
|
|
17
|
-
/** Scans `dir` for agent modules — direct `.ts`/`.js` files, or
|
|
18
|
-
* subdirectories with an `index.ts`/`index.js` (see resolveModulePath) —
|
|
19
|
-
* each expected to export `config`, and either its own `createModelCall`
|
|
20
|
-
* or a `config.model` for one to be synthesized from (see
|
|
21
|
-
* AgentModelConfig's own doc comment). Throws, rather than skipping, on a
|
|
22
|
-
* module that doesn't match that shape or a duplicate AgentConfig.name —
|
|
23
|
-
* both are almost always a bug, not something to silently ignore. */
|
|
24
|
-
export declare function discoverAgents(dir: string): Promise<Map<string, AgentModule>>;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|