@securecoms/agent-runtime 0.6.0 → 0.9.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/README.md +120 -30
- package/dist/bin.js +1781 -452
- package/package.json +2 -2
- package/skills/remember/SKILL.md +0 -13
package/README.md
CHANGED
|
@@ -79,6 +79,66 @@ process (from `--identity`/`SECURECOMS_IDENTITY`) must match both the
|
|
|
79
79
|
identity recorded in the connection file and the identity the local daemon
|
|
80
80
|
reports on its health endpoint. Any mismatch refuses the connection outright.
|
|
81
81
|
|
|
82
|
+
## Execution boundaries
|
|
83
|
+
|
|
84
|
+
Every model request and response is limited to 128 KiB and the complete
|
|
85
|
+
provider exchange has a 180-second deadline. The full model/tool turn has a
|
|
86
|
+
five-minute deadline. The same cancellation signal reaches model fetches,
|
|
87
|
+
network skills, SQLite subprocesses, and Postgres sockets when a turn times
|
|
88
|
+
out, its WebSocket disconnects, or the runtime stops.
|
|
89
|
+
|
|
90
|
+
Turns are serialized per channel because channel memory is mutable. One agent
|
|
91
|
+
may run at most four turns across different channels; additional work is
|
|
92
|
+
refused with a retryable busy response instead of entering an unbounded queue.
|
|
93
|
+
Network skills retain their independent 10-second and 2-MiB fetch boundaries,
|
|
94
|
+
and tool results retain the common 20,000-byte response boundary.
|
|
95
|
+
|
|
96
|
+
### Retry idempotency for external side effects
|
|
97
|
+
|
|
98
|
+
The reachable execution inventory is intentionally narrow. `echo`,
|
|
99
|
+
`current_time`, `web_search`, `fetch_url`, `sql_query`, and GET-only
|
|
100
|
+
`http_request` calls use read grants. The only currently supported
|
|
101
|
+
state-changing surface is a configured `http_request` using POST, PUT, or
|
|
102
|
+
DELETE. Custom scripts and every other current built-in fail closed if they
|
|
103
|
+
are presented with a side-effect grant.
|
|
104
|
+
|
|
105
|
+
A state-changing HTTP call is offered and executed only when an active
|
|
106
|
+
per-turn grant binds all of the following: the tool, a canonical SHA-256 of
|
|
107
|
+
the exact arguments, a confirmation id, an idempotency key, and an expiry.
|
|
108
|
+
The runtime checks this binding both before execution and again inside the
|
|
109
|
+
skill invoker. A read grant never authorizes a state-changing method, and a
|
|
110
|
+
side-effect grant never authorizes GET.
|
|
111
|
+
|
|
112
|
+
Before the external request starts, a per-agent mode-0600 SQLite ledger
|
|
113
|
+
durably binds the idempotency key to the confirmed operation. A completed
|
|
114
|
+
retry returns `already_applied` without repeating the request. A process loss,
|
|
115
|
+
cancelled request, transport failure, or crash between the external response
|
|
116
|
+
and ledger completion leaves an ambiguous claim; retries then fail closed and
|
|
117
|
+
require reconciliation. The ledger stores only identifiers, hashes, states,
|
|
118
|
+
and timestamps—not request bodies, responses, or message content—and refuses
|
|
119
|
+
new operations after 10,000 claims rather than growing without bound.
|
|
120
|
+
|
|
121
|
+
After a crash or host replacement, list unresolved effects without exposing
|
|
122
|
+
request or response content:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
securecoms-agent side-effects list --identity <identity_id> [--data-dir <dir>]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Verify the outcome against the external system using its own operation or
|
|
129
|
+
idempotency record, then bind the decision to every identifier printed by the
|
|
130
|
+
list command:
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
securecoms-agent side-effects resolve --identity <identity_id> [--data-dir <dir>] \
|
|
134
|
+
--idempotency-key <key> --operation-sha256 <digest> \
|
|
135
|
+
--confirmation-id <id> --outcome completed
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Use `--outcome not_applied` only after independently proving the effect did not
|
|
139
|
+
occur; that removes the pre-effect claim and permits one exact retry. `completed`
|
|
140
|
+
keeps the durable suppression and all later retries return `already_applied`.
|
|
141
|
+
|
|
82
142
|
## Configuration
|
|
83
143
|
|
|
84
144
|
All configuration is via `SECURECOMS_*` environment variables (see
|
|
@@ -98,9 +158,12 @@ All configuration is via `SECURECOMS_*` environment variables (see
|
|
|
98
158
|
| `SECURECOMS_DATA_DIR` | `~/.securecoms/agent-runtime` | Root directory for per-channel state |
|
|
99
159
|
| `SECURECOMS_SKILLS_CONFIG` | `<dataDir>/skills.json` (or `--skills-config <path>`) | Path to `skills.json` — named endpoints, databases and flags |
|
|
100
160
|
| `SECURECOMS_LOG_LEVEL` | `info` | One of `debug`, `info`, `warn`, `error` |
|
|
101
|
-
| `SECURECOMS_TOOL_ALLOW` | `echo`, `web_search`, `fetch_url`, `http_request`, `sql_query`, `current_time
|
|
161
|
+
| `SECURECOMS_TOOL_ALLOW` | `echo`, `web_search`, `fetch_url`, `http_request`, `sql_query`, `current_time` | Comma-separated tool allow-list |
|
|
102
162
|
| `SECURECOMS_TOOL_DENY` | unset | Comma-separated tool deny-list (wins over allow) |
|
|
103
163
|
| `SECURECOMS_TOOL_DEFAULT` | `deny` | Fallback policy for a tool matched by neither list |
|
|
164
|
+
| `SECURECOMS_LLM_MAX_OUTPUT_TOKENS` | `8192` | Output-token cap sent on every model request (`max_tokens`; `max_completion_tokens` for `api.openai.com`). Whole number ≥ 1 |
|
|
165
|
+
| `SECURECOMS_LLM_DAILY_CALL_LIMIT` | `2000` | Model requests per UTC day. When spent, each channel gets one "daily usage limit" reply and the provider is not called again until 00:00 UTC. `0` = unlimited |
|
|
166
|
+
| `SECURECOMS_LLM_DAILY_TOKEN_LIMIT` | `5000000` | Provider-reported tokens per UTC day, same behaviour as the call limit. `0` = unlimited. Counters persist in `<dataDir>/llm-budget-<identity>.json` (counts only, no content) |
|
|
104
167
|
|
|
105
168
|
### The LLM source: explicit vs managed
|
|
106
169
|
|
|
@@ -184,6 +247,10 @@ required. `handler` is one of:
|
|
|
184
247
|
A manifest or `SKILL.md` with any other handler shape, or a missing required
|
|
185
248
|
field, is skipped with a warning, and a skill invocation that throws is
|
|
186
249
|
turned into a `tool_failed` tool message rather than dropping the turn.
|
|
250
|
+
Every built-in and script result crosses the same 20,000-byte response
|
|
251
|
+
boundary. Oversized plain text ends with `…[truncated]`; oversized JSON and
|
|
252
|
+
errors remain valid JSON with `truncated: true` instead of being sliced into
|
|
253
|
+
an invalid envelope.
|
|
187
254
|
|
|
188
255
|
### Gating a skill on configuration
|
|
189
256
|
|
|
@@ -205,9 +272,9 @@ the line — for example `requires: [endpoint:crm]` in
|
|
|
205
272
|
|
|
206
273
|
## Curated skills
|
|
207
274
|
|
|
208
|
-
|
|
275
|
+
Six built-in handlers ship with the runtime. All network built-ins refuse
|
|
209
276
|
`localhost` and any private, loopback or link-local resolved address, and
|
|
210
|
-
every tool result is capped at 20
|
|
277
|
+
every tool result is capped at 20,000 UTF-8 bytes (truncated, not an error). A redirect to a
|
|
211
278
|
different origin is followed without the caller's headers and without the
|
|
212
279
|
request body, so a configured header value or a search key can never be handed
|
|
213
280
|
to a host the operator did not name.
|
|
@@ -220,7 +287,6 @@ to a host the operator did not name.
|
|
|
220
287
|
| `web_search` | `query`, `count` (1–10, default 5) | `requires: [search_provider]` — needs a readable, non-empty `SECURECOMS_BRAVE_KEY_FILE` or `SECURECOMS_TAVILY_KEY_FILE`; Brave is used first when both are set. |
|
|
221
288
|
| `http_request` | `name` (a configured `endpoint:<name>`), `path` (a query string is kept, a `#fragment` is dropped), `method` (GET/POST/PUT/DELETE), `body` | `requires: [any_endpoint]`. The model names an endpoint and a path, never a host; a path that would leave the endpoint's `baseUrl` origin is refused. |
|
|
222
289
|
| `sql_query` | `name` (a configured `database:<name>`), `sql` (read-only `SELECT` only; a `;` or a write keyword anywhere in the text — inside a string literal or a comment included — is refused) | `requires: [any_database]`. SQLite or Postgres (`pg` required separately for Postgres). Results capped at 200 rows. |
|
|
223
|
-
| `remember` | `fact` (≤300 chars) | Appends a dated line to the agent-wide `MEMORY.md`. |
|
|
224
290
|
|
|
225
291
|
## skills.json
|
|
226
292
|
|
|
@@ -283,12 +349,16 @@ file that already exists, so a customized `IDENTITY.md` is safe to keep
|
|
|
283
349
|
across a re-init. `securecoms-agent persona show` prints the assembled system
|
|
284
350
|
prompt exactly as a turn would see it, useful for checking an edit landed.
|
|
285
351
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
352
|
+
Legacy `MEMORY.md` files are not active configuration. Earlier runtime versions
|
|
353
|
+
injected one agent-wide file into every channel, which crossed channel
|
|
354
|
+
audiences. On startup the runtime moves each legacy file to a mode-0600
|
|
355
|
+
`MEMORY.quarantined*.md` file in the same directory without overwriting an
|
|
356
|
+
existing quarantine. The quarantined content is never injected or writable by
|
|
357
|
+
a tool. The runtime inventories that quarantine plus inactive per-channel JSON
|
|
358
|
+
stores for the owner-review surface. Review offers a passphrase-encrypted
|
|
359
|
+
export and exact-source deletion; the 90-day clock begins only after the
|
|
360
|
+
machine successfully reports the source. Explicit fact-to-channel assignment
|
|
361
|
+
is a separate migration step and never guesses or fans out an audience.
|
|
292
362
|
|
|
293
363
|
## Managed configuration (from the web app)
|
|
294
364
|
|
|
@@ -307,7 +377,7 @@ managed directory at all behaves exactly as it did before. `skills.json` is
|
|
|
307
377
|
looked up the same way, and re-read on every turn — a new endpoint or a skill
|
|
308
378
|
switched off in the app takes effect on the next message, with no restart.
|
|
309
379
|
|
|
310
|
-
|
|
380
|
+
One deliberate exception:
|
|
311
381
|
|
|
312
382
|
- **The environment still wins for the tool policy.** `SECURECOMS_TOOL_ALLOW`
|
|
313
383
|
overrides the `allow` list in the `tools` block of `skills.json`, so an
|
|
@@ -316,35 +386,55 @@ Two deliberate exceptions:
|
|
|
316
386
|
rather than replacing it: deny is a safety mechanism, so one entry in the
|
|
317
387
|
service unit must not silently un-deny every tool the owner switched off in
|
|
318
388
|
the app. Everything the environment denies stays denied either way.
|
|
319
|
-
- **Writes go to the data dir**, not the managed directory — except `MEMORY.md`,
|
|
320
|
-
which is written wherever the agent already keeps it. An existing
|
|
321
|
-
`<dataDir>/MEMORY.md` is copied into the managed directory once, at startup,
|
|
322
|
-
so the owner can read and prune it in the app.
|
|
323
389
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
390
|
+
Runtime-owned writes go to the data directory, not the managed directory.
|
|
391
|
+
Legacy `MEMORY.md` is handled only by the quarantine behavior described above.
|
|
392
|
+
|
|
393
|
+
The runtime also writes mode-0600 `local-config.json` into the managed directory
|
|
394
|
+
when one exists: what this agent's OWN persona files say, booleans for readable
|
|
395
|
+
search/managed-LLM keys, and a bounded inventory of inert legacy-memory files.
|
|
396
|
+
It is written at startup and rewritten whenever those answers or the inventory
|
|
397
|
+
change. The daemon revalidates current regular-file bytes, removes local paths,
|
|
398
|
+
and only then reports it upward. Nothing in the runtime reads the report back,
|
|
399
|
+
and it holds no key value.
|
|
400
|
+
|
|
401
|
+
### Per-turn channel authorization
|
|
402
|
+
|
|
403
|
+
Installation configuration is only a ceiling. On every inbound message the
|
|
404
|
+
bridge supplies an immutable, server-derived authorization claim containing
|
|
405
|
+
the sender audience, membership state, and channel tool grants. The runtime
|
|
406
|
+
intersects that claim with installed skills, configuration requirements, and
|
|
407
|
+
the local allow/deny gate before showing tools to the model, then repeats the
|
|
408
|
+
same channel-grant check immediately before execution. Missing or malformed
|
|
409
|
+
claims, inactive/unknown membership, and absent grants all fail closed.
|
|
410
|
+
|
|
411
|
+
The live bridge currently issues no channel grants, so no generic tool is
|
|
412
|
+
offered even when it is installed and enabled. Read grants can enable only the
|
|
413
|
+
curated read-only surfaces. The runtime now enforces the exact-operation,
|
|
414
|
+
confirmation, expiry, and durable replay contract described above for future
|
|
415
|
+
side-effect grants; that path remains dormant until an upstream confirmation
|
|
416
|
+
producer deliberately issues such a grant.
|
|
330
417
|
|
|
331
|
-
###
|
|
418
|
+
### The generated tool paragraph is an installation summary
|
|
332
419
|
|
|
333
420
|
The `AGENTS.md` the app delivers ends in a generated paragraph naming the tools
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
421
|
+
configured for the installation, and explicitly tells the model that the
|
|
422
|
+
per-turn offered list is authoritative. The backend derives the installation
|
|
423
|
+
list from saved configuration plus the search-key boolean above; it does not
|
|
424
|
+
see the running process or a turn's channel grants. These things can therefore
|
|
425
|
+
make the installation summary differ from what the runtime offers:
|
|
337
426
|
|
|
338
427
|
- a `SECURECOMS_TOOL_ALLOW` or `SECURECOMS_TOOL_DENY` set in the service unit,
|
|
339
428
|
which the backend cannot see;
|
|
340
429
|
- a customer skill folder whose `requires:` is narrower than the shipped one, so
|
|
341
430
|
the runtime withholds a tool the backend counted;
|
|
342
|
-
- a custom skill the backend knows nothing about, so it
|
|
431
|
+
- a custom skill the backend knows nothing about, so it can be eligible but
|
|
432
|
+
unnamed;
|
|
433
|
+
- the current channel has no matching server-issued read grant.
|
|
343
434
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
a wrong permission.
|
|
435
|
+
The paragraph is therefore an advisory configuration summary, not an authority
|
|
436
|
+
claim. Channel authorization and the local gate are both enforced at call
|
|
437
|
+
time, so a configured but ungranted or denied tool is still refused.
|
|
348
438
|
|
|
349
439
|
## Provenance
|
|
350
440
|
|