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.
Files changed (40) hide show
  1. package/PROTOCOL.md +245 -0
  2. package/README.md +44 -5
  3. package/core/system-skills/composio-large-outputs/SKILL.md +25 -0
  4. package/dist/{cli.d.ts → bin/cli.d.ts} +25 -4
  5. package/dist/{cli.js → bin/cli.js} +131 -16
  6. package/dist/{agent-as-tool.d.ts → core/agent-as-tool.d.ts} +2 -2
  7. package/dist/{agent-as-tool.js → core/agent-as-tool.js} +1 -1
  8. package/dist/core/client.d.ts +113 -0
  9. package/dist/core/client.js +123 -0
  10. package/dist/core/discover-agents.d.ts +45 -0
  11. package/dist/{discover-agents.js → core/discover-agents.js} +11 -3
  12. package/dist/{gateway-tools.d.ts → core/gateway-tools.d.ts} +38 -6
  13. package/dist/{gateway-tools.js → core/gateway-tools.js} +140 -28
  14. package/dist/core/loop-events.d.ts +175 -0
  15. package/dist/core/loop-events.js +1 -0
  16. package/dist/{model-calls → core/model-calls}/anthropic-model-call.d.ts +1 -1
  17. package/dist/{model-calls → core/model-calls}/deepseek-model-call.d.ts +1 -1
  18. package/dist/{model-calls → core/model-calls}/openai-model-call.d.ts +1 -1
  19. package/dist/{model-calls → core/model-calls}/openai-model-call.js +1 -1
  20. package/dist/{run-agent.d.ts → core/run-agent.d.ts} +79 -11
  21. package/dist/{run-agent.js → core/run-agent.js} +242 -60
  22. package/dist/{session-store.d.ts → core/session-store.d.ts} +14 -2
  23. package/dist/{session-store.js → core/session-store.js} +19 -0
  24. package/dist/core/system-tools/ask_user.d.ts +72 -0
  25. package/dist/core/system-tools/ask_user.js +136 -0
  26. package/dist/core/system-tools/index.d.ts +3 -0
  27. package/dist/core/system-tools/index.js +12 -0
  28. package/dist/core/system-tools/read_file.d.ts +28 -0
  29. package/dist/core/system-tools/read_file.js +64 -0
  30. package/dist/{vector-index.js → core/vector-index.js} +1 -1
  31. package/dist/index.d.ts +19 -16
  32. package/dist/index.js +16 -9
  33. package/package.json +34 -28
  34. package/protocol/loop-event.schema.json +257 -0
  35. package/dist/discover-agents.d.ts +0 -24
  36. /package/dist/{agent-config.d.ts → core/agent-config.d.ts} +0 -0
  37. /package/dist/{agent-config.js → core/agent-config.js} +0 -0
  38. /package/dist/{model-calls → core/model-calls}/anthropic-model-call.js +0 -0
  39. /package/dist/{model-calls → core/model-calls}/deepseek-model-call.js +0 -0
  40. /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