@cotal-ai/core 0.1.0 → 0.1.3
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/agent-file.d.ts +8 -0
- package/dist/agent-file.d.ts.map +1 -1
- package/dist/agent-file.js +62 -2
- package/dist/agent-file.js.map +1 -1
- package/dist/channels.d.ts +68 -0
- package/dist/channels.d.ts.map +1 -0
- package/dist/channels.js +140 -0
- package/dist/channels.js.map +1 -0
- package/dist/endpoint.d.ts +127 -3
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoint.js +513 -30
- package/dist/endpoint.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/provision.d.ts.map +1 -1
- package/dist/provision.js +36 -4
- package/dist/provision.js.map +1 -1
- package/dist/runtime.d.ts +66 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +2 -0
- package/dist/runtime.js.map +1 -0
- package/dist/spaces.d.ts +25 -0
- package/dist/spaces.d.ts.map +1 -0
- package/dist/spaces.js +96 -0
- package/dist/spaces.js.map +1 -0
- package/dist/streams.d.ts +16 -0
- package/dist/streams.d.ts.map +1 -1
- package/dist/streams.js +35 -5
- package/dist/streams.js.map +1 -1
- package/dist/subjects.d.ts +11 -0
- package/dist/subjects.d.ts.map +1 -1
- package/dist/subjects.js +13 -2
- package/dist/subjects.js.map +1 -1
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -1
package/dist/agent-file.d.ts
CHANGED
|
@@ -12,11 +12,19 @@ export interface AgentDef {
|
|
|
12
12
|
publish?: string[];
|
|
13
13
|
/** Model override handed to the agent CLI (e.g. `claude --model`). */
|
|
14
14
|
model?: string;
|
|
15
|
+
/** Frontmatter keys not modelled above, kept verbatim so a connector can read its own launcher
|
|
16
|
+
* hints without core knowing about each one (e.g. the OpenCode face viewer's `face:` avatar id). */
|
|
17
|
+
meta?: Record<string, string>;
|
|
15
18
|
/** Markdown body — the agent's persona / appended system prompt. */
|
|
16
19
|
persona?: string;
|
|
17
20
|
}
|
|
18
21
|
/** Load and parse an agent definition file (Markdown + `---` frontmatter). */
|
|
19
22
|
export declare function loadAgentFile(path: string): AgentDef;
|
|
23
|
+
/** Write an agent definition back to disk in the form {@link loadAgentFile} reads:
|
|
24
|
+
* the set frontmatter fields followed by the persona body. Round-trips through the
|
|
25
|
+
* parser; creates parent dirs. The runtime persona-definition path uses this to
|
|
26
|
+
* persist a peer-defined agent as config. */
|
|
27
|
+
export declare function saveAgentFile(path: string, def: AgentDef): void;
|
|
20
28
|
/** Resolve a name-or-path to an agent file. A path (absolute, contains a slash,
|
|
21
29
|
* or ends in `.md`) is used as given; a bare name maps to the directory
|
|
22
30
|
* convention `<root>/.cotal/agents/<name>.md`. */
|
package/dist/agent-file.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-file.d.ts","sourceRoot":"","sources":["../src/agent-file.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent-file.d.ts","sourceRoot":"","sources":["../src/agent-file.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;8FAE0F;IAC1F,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;yGACqG;IACrG,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmCD,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CA0CpD;AAED;;;8CAG8C;AAC9C,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CAe/D;AAmBD;;mDAEmD;AACnD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAItE"}
|
package/dist/agent-file.js
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* channels: [general] # channels this agent subscribes to (read)
|
|
11
11
|
* publish: [general] # channels this agent may post to (write); omit = same as channels
|
|
12
12
|
* model: opus # optional CLI/model override
|
|
13
|
+
* face: sven # any unmodelled key is kept verbatim in AgentDef.meta — e.g. the
|
|
14
|
+
* # OpenCode connector reads meta.face for its avatar viewer
|
|
13
15
|
* ---
|
|
14
16
|
* <the Markdown body is the persona — an appended system prompt>
|
|
15
17
|
*
|
|
@@ -18,8 +20,8 @@
|
|
|
18
20
|
* session reads its own card from it. Part of the wire contract's onboarding
|
|
19
21
|
* half, alongside the join link.
|
|
20
22
|
*/
|
|
21
|
-
import { readFileSync } from "node:fs";
|
|
22
|
-
import { isAbsolute, join, resolve } from "node:path";
|
|
23
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
24
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
23
25
|
/** Strip wrapping quotes from a scalar value. */
|
|
24
26
|
function unquote(v) {
|
|
25
27
|
if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'")))
|
|
@@ -81,6 +83,13 @@ export function loadAgentFile(path) {
|
|
|
81
83
|
const kind = str("kind");
|
|
82
84
|
if (kind && kind !== "agent" && kind !== "endpoint")
|
|
83
85
|
throw new Error(`agent file ${path}: "kind" must be "agent" or "endpoint"`);
|
|
86
|
+
// Sweep every scalar frontmatter key we don't model into meta, verbatim — connector hints
|
|
87
|
+
// (face, etc.) ride here so core stays ignorant of surface-specific keys.
|
|
88
|
+
const known = new Set(["name", "role", "kind", "description", "tags", "channels", "publish", "model"]);
|
|
89
|
+
const meta = {};
|
|
90
|
+
for (const [k, v] of Object.entries(fm))
|
|
91
|
+
if (!known.has(k) && typeof v === "string")
|
|
92
|
+
meta[k] = v;
|
|
84
93
|
return {
|
|
85
94
|
name,
|
|
86
95
|
role: str("role"),
|
|
@@ -90,9 +99,60 @@ export function loadAgentFile(path) {
|
|
|
90
99
|
channels: list("channels"),
|
|
91
100
|
publish: list("publish"),
|
|
92
101
|
model: str("model"),
|
|
102
|
+
meta: Object.keys(meta).length ? meta : undefined,
|
|
93
103
|
persona: persona || undefined,
|
|
94
104
|
};
|
|
95
105
|
}
|
|
106
|
+
/** Write an agent definition back to disk in the form {@link loadAgentFile} reads:
|
|
107
|
+
* the set frontmatter fields followed by the persona body. Round-trips through the
|
|
108
|
+
* parser; creates parent dirs. The runtime persona-definition path uses this to
|
|
109
|
+
* persist a peer-defined agent as config. */
|
|
110
|
+
export function saveAgentFile(path, def) {
|
|
111
|
+
if (!def.name)
|
|
112
|
+
throw new Error('saveAgentFile: "name" is required');
|
|
113
|
+
const lines = ["---", `name: ${fmScalar(def.name)}`];
|
|
114
|
+
if (def.role)
|
|
115
|
+
lines.push(`role: ${fmScalar(def.role)}`);
|
|
116
|
+
if (def.kind)
|
|
117
|
+
lines.push(`kind: ${fmScalar(def.kind)}`);
|
|
118
|
+
if (def.description)
|
|
119
|
+
lines.push(`description: ${fmScalar(def.description)}`);
|
|
120
|
+
if (def.tags?.length)
|
|
121
|
+
lines.push(`tags: [${def.tags.map(fmItem).join(", ")}]`);
|
|
122
|
+
if (def.channels?.length)
|
|
123
|
+
lines.push(`channels: [${def.channels.map(fmItem).join(", ")}]`);
|
|
124
|
+
if (def.publish?.length)
|
|
125
|
+
lines.push(`publish: [${def.publish.map(fmItem).join(", ")}]`);
|
|
126
|
+
if (def.model)
|
|
127
|
+
lines.push(`model: ${fmScalar(def.model)}`);
|
|
128
|
+
if (def.meta)
|
|
129
|
+
for (const [k, v] of Object.entries(def.meta))
|
|
130
|
+
lines.push(`${k}: ${fmScalar(v)}`);
|
|
131
|
+
lines.push("---");
|
|
132
|
+
const body = def.persona ? `${def.persona.trim()}\n` : "";
|
|
133
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
134
|
+
writeFileSync(path, `${lines.join("\n")}\n\n${body}`);
|
|
135
|
+
}
|
|
136
|
+
/** Render a frontmatter scalar so {@link loadAgentFile} reads it back unchanged. Quotes values
|
|
137
|
+
* the parser would otherwise misread (a leading `[`, a `,`/`:`/`#`, edge whitespace, or empty);
|
|
138
|
+
* throws on values the line-based format can't represent (a newline, or both quote styles). */
|
|
139
|
+
function fmScalar(value) {
|
|
140
|
+
if (/[\r\n]/.test(value))
|
|
141
|
+
throw new Error(`saveAgentFile: value cannot contain a newline: ${JSON.stringify(value)}`);
|
|
142
|
+
if (value !== "" && value === value.trim() && !/^[[]/.test(value) && !/[,:#"']/.test(value))
|
|
143
|
+
return value;
|
|
144
|
+
if (!value.includes('"'))
|
|
145
|
+
return `"${value}"`;
|
|
146
|
+
if (!value.includes("'"))
|
|
147
|
+
return `'${value}'`;
|
|
148
|
+
throw new Error(`saveAgentFile: value cannot contain both quote styles: ${JSON.stringify(value)}`);
|
|
149
|
+
}
|
|
150
|
+
/** A list item additionally cannot hold a comma — the parser splits on `,` before unquoting. */
|
|
151
|
+
function fmItem(value) {
|
|
152
|
+
if (value.includes(","))
|
|
153
|
+
throw new Error(`saveAgentFile: list item cannot contain a comma: ${JSON.stringify(value)}`);
|
|
154
|
+
return fmScalar(value);
|
|
155
|
+
}
|
|
96
156
|
/** Resolve a name-or-path to an agent file. A path (absolute, contains a slash,
|
|
97
157
|
* or ends in `.md`) is used as given; a bare name maps to the directory
|
|
98
158
|
* convention `<root>/.cotal/agents/<name>.md`. */
|
package/dist/agent-file.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-file.js","sourceRoot":"","sources":["../src/agent-file.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"agent-file.js","sourceRoot":"","sources":["../src/agent-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel registry — the read/write helpers over the per-space channels KV bucket.
|
|
3
|
+
*
|
|
4
|
+
* The bucket holds one {@link ChannelConfig} per channel (key = the concrete channel token)
|
|
5
|
+
* plus the space-wide defaults under {@link CHANNEL_DEFAULTS_KEY}. Writes are **privileged**
|
|
6
|
+
* (manager / `cotal up` / `cotal channels`); agents read it (the live cache lives on the
|
|
7
|
+
* endpoint). Because description/instructions reach the model, both text fields are bounded
|
|
8
|
+
* here and oversize is **rejected at the write path** — never silently truncated.
|
|
9
|
+
*/
|
|
10
|
+
import { type KV } from "@nats-io/kv";
|
|
11
|
+
import { type NatsConnection } from "@nats-io/transport-node";
|
|
12
|
+
import type { ChannelConfig, ChannelDefaults } from "./types.js";
|
|
13
|
+
/** The declarative channel-config file read at `cotal up` to seed the registry. */
|
|
14
|
+
export interface ChannelRegistryFile {
|
|
15
|
+
defaults?: ChannelDefaults;
|
|
16
|
+
/** Map of channel token → its config. */
|
|
17
|
+
channels?: Record<string, ChannelConfig>;
|
|
18
|
+
}
|
|
19
|
+
/** Length caps on the model-facing registry text — unbounded text would stuff every agent's
|
|
20
|
+
* context and bloat the KV, so a write past these throws rather than clamps. */
|
|
21
|
+
export declare const MAX_CHANNEL_DESCRIPTION = 200;
|
|
22
|
+
export declare const MAX_CHANNEL_INSTRUCTIONS = 2000;
|
|
23
|
+
/** Throw if a config is invalid: oversize text (rejected, never clamped — a write past the cap
|
|
24
|
+
* is a caller bug) or an unparseable `replayWindow`. */
|
|
25
|
+
export declare function validateChannelConfig(cfg: ChannelConfig): void;
|
|
26
|
+
/** Parse a duration like `"24h"`, `"30m"`, `"7d"`, `"90s"` into milliseconds. Throws on a bad
|
|
27
|
+
* format — a typo'd window must fail loud, not silently mean "no window". */
|
|
28
|
+
export declare function parseDuration(s: string): number;
|
|
29
|
+
/** Effective replay-on-join policy for a channel: per-channel override ?? space default ??
|
|
30
|
+
* `true`. Default-true preserves Cotal's original always-replay behavior. */
|
|
31
|
+
export declare function effectiveReplay(cfg: ChannelConfig | undefined, defaults: ChannelDefaults | undefined): boolean;
|
|
32
|
+
/** Effective backfill window in ms (per-channel ?? space default), or undefined for "the full
|
|
33
|
+
* retained window". Only meaningful when {@link effectiveReplay} is true. */
|
|
34
|
+
export declare function effectiveReplayWindowMs(cfg: ChannelConfig | undefined, defaults: ChannelDefaults | undefined): number | undefined;
|
|
35
|
+
/** Open the channels registry bucket. Auth mode (creds present) OPENs the bucket pre-created
|
|
36
|
+
* at `cotal up`; open dev mode lazily CREATEs it. Mirrors the presence-bucket open/create
|
|
37
|
+
* split (and, like presence, agents are denied KV stream-create so they must OPEN). */
|
|
38
|
+
export declare function openChannelRegistry(nc: NatsConnection, space: string, opts?: {
|
|
39
|
+
create?: boolean;
|
|
40
|
+
}): Promise<KV>;
|
|
41
|
+
/** Read one channel's config (or undefined if unset/deleted). */
|
|
42
|
+
export declare function readChannelConfig(kv: KV, channel: string): Promise<ChannelConfig | undefined>;
|
|
43
|
+
/** Read the space-wide defaults (or undefined if unset). */
|
|
44
|
+
export declare function readChannelDefaults(kv: KV): Promise<ChannelDefaults | undefined>;
|
|
45
|
+
/** Privileged write of a channel's config. **Merges** over any existing entry so a partial
|
|
46
|
+
* set (e.g. `--desc` only) doesn't wipe `replay`. Validated before the put. */
|
|
47
|
+
export declare function writeChannelConfig(kv: KV, channel: string, patch: ChannelConfig): Promise<void>;
|
|
48
|
+
/** Privileged write of the space-wide defaults (merged over any existing). */
|
|
49
|
+
export declare function writeChannelDefaults(kv: KV, patch: ChannelDefaults): Promise<void>;
|
|
50
|
+
/** Connect (with the given privileged creds, or open if none), seed the registry from a
|
|
51
|
+
* declarative {@link ChannelRegistryFile} (defaults + per-channel config, merged), disconnect.
|
|
52
|
+
* Used by `cotal up` to seed once at setup, and by `cotal channels` for runtime writes.
|
|
53
|
+
* Each field in the file overwrites that field in the registry; unspecified fields are kept. */
|
|
54
|
+
export declare function seedChannelRegistry(opts: {
|
|
55
|
+
servers: string;
|
|
56
|
+
space: string;
|
|
57
|
+
creds?: string;
|
|
58
|
+
file: ChannelRegistryFile;
|
|
59
|
+
}): Promise<void>;
|
|
60
|
+
/** Connect, read the whole registry (defaults + every channel entry) into a
|
|
61
|
+
* {@link ChannelRegistryFile}, disconnect. The read side of {@link seedChannelRegistry},
|
|
62
|
+
* used by `cotal channels list`. */
|
|
63
|
+
export declare function readChannelRegistry(opts: {
|
|
64
|
+
servers: string;
|
|
65
|
+
space: string;
|
|
66
|
+
creds?: string;
|
|
67
|
+
}): Promise<ChannelRegistryFile>;
|
|
68
|
+
//# sourceMappingURL=channels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAO,KAAK,EAAE,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE3F,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEjE,mFAAmF;AACnF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAC1C;AAED;iFACiF;AACjF,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C;yDACyD;AACzD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAU9D;AAED;8EAC8E;AAC9E,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED;8EAC8E;AAC9E,wBAAgB,eAAe,CAC7B,GAAG,EAAE,aAAa,GAAG,SAAS,EAC9B,QAAQ,EAAE,eAAe,GAAG,SAAS,GACpC,OAAO,CAET;AAED;8EAC8E;AAC9E,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,aAAa,GAAG,SAAS,EAC9B,QAAQ,EAAE,eAAe,GAAG,SAAS,GACpC,MAAM,GAAG,SAAS,CAGpB;AAED;;wFAEwF;AACxF,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,MAAM,EACb,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9B,OAAO,CAAC,EAAE,CAAC,CAGb;AAED,iEAAiE;AACjE,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAEpC;AAED,4DAA4D;AAC5D,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAEtF;AAED;gFACgF;AAChF,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,8EAA8E;AAC9E,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxF;AAYD;;;iGAGiG;AACjG,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,mBAAmB,CAAC;CAC3B,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB;AAED;;qCAEqC;AACrC,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAuB/B"}
|
package/dist/channels.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel registry — the read/write helpers over the per-space channels KV bucket.
|
|
3
|
+
*
|
|
4
|
+
* The bucket holds one {@link ChannelConfig} per channel (key = the concrete channel token)
|
|
5
|
+
* plus the space-wide defaults under {@link CHANNEL_DEFAULTS_KEY}. Writes are **privileged**
|
|
6
|
+
* (manager / `cotal up` / `cotal channels`); agents read it (the live cache lives on the
|
|
7
|
+
* endpoint). Because description/instructions reach the model, both text fields are bounded
|
|
8
|
+
* here and oversize is **rejected at the write path** — never silently truncated.
|
|
9
|
+
*/
|
|
10
|
+
import { Kvm } from "@nats-io/kv";
|
|
11
|
+
import { connect, credsAuthenticator } from "@nats-io/transport-node";
|
|
12
|
+
import { channelBucket, CHANNEL_DEFAULTS_KEY } from "./subjects.js";
|
|
13
|
+
/** Length caps on the model-facing registry text — unbounded text would stuff every agent's
|
|
14
|
+
* context and bloat the KV, so a write past these throws rather than clamps. */
|
|
15
|
+
export const MAX_CHANNEL_DESCRIPTION = 200;
|
|
16
|
+
export const MAX_CHANNEL_INSTRUCTIONS = 2000;
|
|
17
|
+
/** Throw if a config is invalid: oversize text (rejected, never clamped — a write past the cap
|
|
18
|
+
* is a caller bug) or an unparseable `replayWindow`. */
|
|
19
|
+
export function validateChannelConfig(cfg) {
|
|
20
|
+
if (cfg.description !== undefined && cfg.description.length > MAX_CHANNEL_DESCRIPTION)
|
|
21
|
+
throw new Error(`channel description too long (${cfg.description.length} > ${MAX_CHANNEL_DESCRIPTION} chars)`);
|
|
22
|
+
if (cfg.instructions !== undefined && cfg.instructions.length > MAX_CHANNEL_INSTRUCTIONS)
|
|
23
|
+
throw new Error(`channel instructions too long (${cfg.instructions.length} > ${MAX_CHANNEL_INSTRUCTIONS} chars)`);
|
|
24
|
+
if (cfg.replayWindow !== undefined)
|
|
25
|
+
parseDuration(cfg.replayWindow); // throws if unparseable
|
|
26
|
+
}
|
|
27
|
+
/** Parse a duration like `"24h"`, `"30m"`, `"7d"`, `"90s"` into milliseconds. Throws on a bad
|
|
28
|
+
* format — a typo'd window must fail loud, not silently mean "no window". */
|
|
29
|
+
export function parseDuration(s) {
|
|
30
|
+
const m = /^(\d+)(s|m|h|d)$/.exec(s.trim());
|
|
31
|
+
if (!m)
|
|
32
|
+
throw new Error(`invalid duration "${s}" — expected <number><s|m|h|d>, e.g. "24h"`);
|
|
33
|
+
const n = Number(m[1]);
|
|
34
|
+
const unit = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000 }[m[2]];
|
|
35
|
+
return n * unit;
|
|
36
|
+
}
|
|
37
|
+
/** Effective replay-on-join policy for a channel: per-channel override ?? space default ??
|
|
38
|
+
* `true`. Default-true preserves Cotal's original always-replay behavior. */
|
|
39
|
+
export function effectiveReplay(cfg, defaults) {
|
|
40
|
+
return cfg?.replay ?? defaults?.replay ?? true;
|
|
41
|
+
}
|
|
42
|
+
/** Effective backfill window in ms (per-channel ?? space default), or undefined for "the full
|
|
43
|
+
* retained window". Only meaningful when {@link effectiveReplay} is true. */
|
|
44
|
+
export function effectiveReplayWindowMs(cfg, defaults) {
|
|
45
|
+
const w = cfg?.replayWindow ?? defaults?.replayWindow;
|
|
46
|
+
return w === undefined ? undefined : parseDuration(w);
|
|
47
|
+
}
|
|
48
|
+
/** Open the channels registry bucket. Auth mode (creds present) OPENs the bucket pre-created
|
|
49
|
+
* at `cotal up`; open dev mode lazily CREATEs it. Mirrors the presence-bucket open/create
|
|
50
|
+
* split (and, like presence, agents are denied KV stream-create so they must OPEN). */
|
|
51
|
+
export async function openChannelRegistry(nc, space, opts = {}) {
|
|
52
|
+
const kvm = new Kvm(nc);
|
|
53
|
+
return opts.create ? kvm.create(channelBucket(space)) : kvm.open(channelBucket(space));
|
|
54
|
+
}
|
|
55
|
+
/** Read one channel's config (or undefined if unset/deleted). */
|
|
56
|
+
export async function readChannelConfig(kv, channel) {
|
|
57
|
+
return decode(kv, channel);
|
|
58
|
+
}
|
|
59
|
+
/** Read the space-wide defaults (or undefined if unset). */
|
|
60
|
+
export async function readChannelDefaults(kv) {
|
|
61
|
+
return decode(kv, CHANNEL_DEFAULTS_KEY);
|
|
62
|
+
}
|
|
63
|
+
/** Privileged write of a channel's config. **Merges** over any existing entry so a partial
|
|
64
|
+
* set (e.g. `--desc` only) doesn't wipe `replay`. Validated before the put. */
|
|
65
|
+
export async function writeChannelConfig(kv, channel, patch) {
|
|
66
|
+
validateChannelConfig(patch);
|
|
67
|
+
const merged = { ...(await readChannelConfig(kv, channel)), ...patch };
|
|
68
|
+
await kv.put(channel, JSON.stringify(merged));
|
|
69
|
+
}
|
|
70
|
+
/** Privileged write of the space-wide defaults (merged over any existing). */
|
|
71
|
+
export async function writeChannelDefaults(kv, patch) {
|
|
72
|
+
const merged = { ...(await readChannelDefaults(kv)), ...patch };
|
|
73
|
+
await kv.put(CHANNEL_DEFAULTS_KEY, JSON.stringify(merged));
|
|
74
|
+
}
|
|
75
|
+
async function decode(kv, key) {
|
|
76
|
+
const e = await kv.get(key);
|
|
77
|
+
if (!e || e.operation === "DEL" || e.operation === "PURGE")
|
|
78
|
+
return undefined;
|
|
79
|
+
try {
|
|
80
|
+
return e.json();
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Connect (with the given privileged creds, or open if none), seed the registry from a
|
|
87
|
+
* declarative {@link ChannelRegistryFile} (defaults + per-channel config, merged), disconnect.
|
|
88
|
+
* Used by `cotal up` to seed once at setup, and by `cotal channels` for runtime writes.
|
|
89
|
+
* Each field in the file overwrites that field in the registry; unspecified fields are kept. */
|
|
90
|
+
export async function seedChannelRegistry(opts) {
|
|
91
|
+
const nc = await connect({
|
|
92
|
+
servers: opts.servers,
|
|
93
|
+
...(opts.creds
|
|
94
|
+
? { authenticator: credsAuthenticator(new TextEncoder().encode(opts.creds)) }
|
|
95
|
+
: {}),
|
|
96
|
+
});
|
|
97
|
+
try {
|
|
98
|
+
// The seed path is privileged (manager creds or open) so it may CREATE the bucket — this
|
|
99
|
+
// makes `cotal channels` work on a space whose bucket wasn't pre-created (e.g. one set up
|
|
100
|
+
// before this feature). Idempotent when `cotal up` already created it.
|
|
101
|
+
const kv = await openChannelRegistry(nc, opts.space, { create: true });
|
|
102
|
+
if (opts.file.defaults)
|
|
103
|
+
await writeChannelDefaults(kv, opts.file.defaults);
|
|
104
|
+
for (const [channel, cfg] of Object.entries(opts.file.channels ?? {}))
|
|
105
|
+
await writeChannelConfig(kv, channel, cfg);
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
await nc.drain();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** Connect, read the whole registry (defaults + every channel entry) into a
|
|
112
|
+
* {@link ChannelRegistryFile}, disconnect. The read side of {@link seedChannelRegistry},
|
|
113
|
+
* used by `cotal channels list`. */
|
|
114
|
+
export async function readChannelRegistry(opts) {
|
|
115
|
+
const nc = await connect({
|
|
116
|
+
servers: opts.servers,
|
|
117
|
+
...(opts.creds
|
|
118
|
+
? { authenticator: credsAuthenticator(new TextEncoder().encode(opts.creds)) }
|
|
119
|
+
: {}),
|
|
120
|
+
});
|
|
121
|
+
try {
|
|
122
|
+
const kv = await openChannelRegistry(nc, opts.space, { create: true });
|
|
123
|
+
const channels = {};
|
|
124
|
+
let defaults;
|
|
125
|
+
for await (const key of await kv.keys()) {
|
|
126
|
+
if (key === CHANNEL_DEFAULTS_KEY) {
|
|
127
|
+
defaults = await readChannelDefaults(kv);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const cfg = await readChannelConfig(kv, key);
|
|
131
|
+
if (cfg)
|
|
132
|
+
channels[key] = cfg;
|
|
133
|
+
}
|
|
134
|
+
return { defaults, channels };
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
await nc.drain();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=channels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.js","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"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"}
|
package/dist/endpoint.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
|
-
import type { AgentCard, ControlReply, ControlRequest, EndpointRef, Part, Presence, PresenceStatus, CotalMessage } from "./types.js";
|
|
2
|
+
import type { AgentCard, ChannelConfig, ControlReply, ControlRequest, EndpointRef, Part, Presence, PresenceStatus, CotalMessage } from "./types.js";
|
|
3
3
|
export declare const DEFAULT_SERVER = "nats://127.0.0.1:4222";
|
|
4
|
+
/** Space joined when none is given on the CLI (the `cotal-<space>` cmux tab, etc.). */
|
|
5
|
+
export declare const DEFAULT_SPACE = "main";
|
|
4
6
|
export interface EndpointOptions {
|
|
5
7
|
/** The collaboration to join. */
|
|
6
8
|
space: string;
|
|
@@ -36,6 +38,15 @@ export interface EndpointOptions {
|
|
|
36
38
|
/** Retire this instance's durable consumers after it's been gone this long (ms). */
|
|
37
39
|
inactiveThresholdMs?: number;
|
|
38
40
|
}
|
|
41
|
+
/** A peer subscribed to a channel — broker truth (a chat-stream consumer) joined with
|
|
42
|
+
* presence for liveness. `live: false` is a stale ghost: the durable lingers (reconnect
|
|
43
|
+
* grace) but presence says the peer is gone/offline. */
|
|
44
|
+
export interface ChannelMember {
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
role?: string;
|
|
48
|
+
live: boolean;
|
|
49
|
+
}
|
|
39
50
|
/**
|
|
40
51
|
* Events: "message" (CotalMessage), "presence" (PresenceEvent), "roster" (Presence[]), "error" (Error).
|
|
41
52
|
*
|
|
@@ -65,6 +76,15 @@ export declare class CotalEndpoint extends EventEmitter {
|
|
|
65
76
|
private js?;
|
|
66
77
|
private jsm?;
|
|
67
78
|
private kv?;
|
|
79
|
+
private channelKv?;
|
|
80
|
+
/** Live local cache of the channel registry (key = channel token), kept by a KV watch. */
|
|
81
|
+
private readonly channelConfigs;
|
|
82
|
+
private channelDefaults;
|
|
83
|
+
/** Per-subscription join watermark: the stream frontier captured when a channel was joined.
|
|
84
|
+
* The tail ack-drops chat messages with `seq <= watermark` (suppresses pre-join history for
|
|
85
|
+
* a lagging joiner + dedups the backfill overlap). Keyed by the subscription pattern (may be
|
|
86
|
+
* wildcard), so the drop matches every concrete channel the pattern subsumes. */
|
|
87
|
+
private readonly joinSeq;
|
|
68
88
|
private readonly subs;
|
|
69
89
|
private readonly streamMsgs;
|
|
70
90
|
private heartbeatTimer?;
|
|
@@ -110,12 +130,56 @@ export declare class CotalEndpoint extends EventEmitter {
|
|
|
110
130
|
getRoster(): Presence[];
|
|
111
131
|
setActivity(activity: string): Promise<void>;
|
|
112
132
|
setStatus(status: PresenceStatus): Promise<void>;
|
|
113
|
-
/**
|
|
114
|
-
|
|
133
|
+
/** This channel's registry config from the live local cache (undefined if unset). */
|
|
134
|
+
getChannelConfig(channel: string): ChannelConfig | undefined;
|
|
135
|
+
/** Effective replay-on-join policy for a channel: per-channel override ?? space default ??
|
|
136
|
+
* true. Reads the live cache, so it reflects runtime registry edits. */
|
|
137
|
+
channelReplay(channel: string): boolean;
|
|
138
|
+
/** The channels this endpoint is currently subscribed to (live — reflects join/leave). */
|
|
139
|
+
joinedChannels(): string[];
|
|
140
|
+
/**
|
|
141
|
+
* Join a channel mid-session: add it to our chat durable's `filter_subjects` (same durable,
|
|
142
|
+
* same ack-floor, no teardown — `update` rides the self-scoped create grant), capture the
|
|
143
|
+
* stream frontier as this channel's join watermark, and backfill its history if replay is on.
|
|
144
|
+
* Idempotent: re-joining a channel already in our filter is a no-op (no re-backfill). Returns
|
|
145
|
+
* the number of historical messages backfilled (emitted as `historical` "message" events).
|
|
146
|
+
*/
|
|
147
|
+
joinChannel(channel: string): Promise<{
|
|
148
|
+
joined: boolean;
|
|
149
|
+
backfilled: number;
|
|
150
|
+
}>;
|
|
151
|
+
/** Leave a channel mid-session: drop it from the durable's `filter_subjects`. Refuses to leave
|
|
152
|
+
* the *last* channel (an empty filter would match every chat subject — the opposite of
|
|
153
|
+
* leaving). Returns whether anything changed. */
|
|
154
|
+
leaveChannel(channel: string): Promise<{
|
|
155
|
+
left: boolean;
|
|
156
|
+
}>;
|
|
157
|
+
/** One coherent channel model for dashboards: every channel that has messages OR a registry
|
|
158
|
+
* entry (configured-but-empty), each tagged with its {@link ChannelConfig}. Works even on
|
|
159
|
+
* observer endpoints (no consumers needed). */
|
|
115
160
|
listChannels(): Promise<{
|
|
116
161
|
channel: string;
|
|
117
162
|
messages: number;
|
|
163
|
+
config?: ChannelConfig;
|
|
118
164
|
}[]>;
|
|
165
|
+
/**
|
|
166
|
+
* Who is subscribed to a channel — **broker truth, not self-report**. In Cotal a peer
|
|
167
|
+
* joins a channel by creating a chat-stream durable consumer (`chat_<id>`,
|
|
168
|
+
* `filter_subjects` = its channels), so `consumers.list(CHAT)` already records the real
|
|
169
|
+
* membership; we join it with presence so a lingering durable for a gone peer shows as a
|
|
170
|
+
* stale ghost (`live: false`) rather than a phantom listener.
|
|
171
|
+
*
|
|
172
|
+
* `channelMembers("review")` → that channel's members; `channelMembers()` → every channel
|
|
173
|
+
* mapped to its members. A member on a wildcard (`team.>`) counts for every concrete
|
|
174
|
+
* channel it subsumes (`team.backend`) — membership is the *effective subscription*.
|
|
175
|
+
*
|
|
176
|
+
* Privileged read: `consumers.list` needs `$JS.API.CONSUMER.LIST.<chat stream>`, which only
|
|
177
|
+
* the allow-all manager profile holds today (agents, observer, and admin are all denied), so
|
|
178
|
+
* this is not an agent-facing capability — serving it from a dashboard profile is a one-line
|
|
179
|
+
* ACL grant away.
|
|
180
|
+
*/
|
|
181
|
+
channelMembers(channel: string): Promise<ChannelMember[]>;
|
|
182
|
+
channelMembers(): Promise<Map<string, ChannelMember[]>>;
|
|
119
183
|
/** Fetch recent messages from a channel's JetStream backlog. */
|
|
120
184
|
channelHistory(channel: string, opts?: {
|
|
121
185
|
limit?: number;
|
|
@@ -165,8 +229,68 @@ export declare class CotalEndpoint extends EventEmitter {
|
|
|
165
229
|
private startConsumers;
|
|
166
230
|
/** Drive one consumer: decode, drop our own echo, and hand each message to listeners with ack control. */
|
|
167
231
|
private pump;
|
|
232
|
+
/** The highest join watermark among the joined subscriptions that cover `concreteChannel`
|
|
233
|
+
* (a wildcard sub like `team.>` covers `team.backend`), or undefined if none — the tail
|
|
234
|
+
* drops a chat message with `seq <= ` this. */
|
|
235
|
+
private dropWatermark;
|
|
236
|
+
/** The durable's info (rebind) or null (fresh — 404). Gates create/backfill to the join event
|
|
237
|
+
* and exposes the current `filter_subjects` for restart reconciliation. */
|
|
238
|
+
private consumerInfo;
|
|
239
|
+
/** Current frontier (last sequence) of the chat stream — a channel's join watermark, and the
|
|
240
|
+
* focus-watermark a connector captures on entering `focus` (recall reads ambient after it). */
|
|
241
|
+
chatFrontier(): Promise<number>;
|
|
242
|
+
/** Phase 1 of a join — arm each channel's tail-drop watermark at the current frontier. MUST run
|
|
243
|
+
* BEFORE the filter flip (consumers.update, or pump on a fresh create) so the tail can never
|
|
244
|
+
* carry a just-joined message un-watermarked — which would double-emit it (live + backfill).
|
|
245
|
+
* Returns the per-channel frontiers for {@link backfillArmed}. */
|
|
246
|
+
private armJoin;
|
|
247
|
+
/** Phase 2 of a join — backfill each armed channel's history up to its frontier (replay-gated),
|
|
248
|
+
* AFTER the filter flip. Returns the total backfilled. */
|
|
249
|
+
private backfillArmed;
|
|
250
|
+
/** Replay policy + backfill window read straight from the registry bucket (vs the watch cache)
|
|
251
|
+
* — the authoritative read for a join decision (a join is infrequent, and at startup the async
|
|
252
|
+
* cache may not have caught up). Falls to the built-in default only with no registry open. */
|
|
253
|
+
private joinPolicyFresh;
|
|
254
|
+
/** Read a channel's retained history up to `upToSeq` via JetStream **Direct Get** (a read
|
|
255
|
+
* verb — no consumer create, so it rides a read-only grant) and emit each message as a
|
|
256
|
+
* `historical` "message" event. `sinceMs` bounds how far back via a native Direct-Get
|
|
257
|
+
* `start_time` (now − window); unset ⇒ the full retained window. New messages (`seq > upToSeq`)
|
|
258
|
+
* are skipped — the live tail owns them. Pages the batch API; the ack handle is a no-op. */
|
|
259
|
+
private backfillChannel;
|
|
260
|
+
/**
|
|
261
|
+
* Replay-gated pull of a channel's retained ambient from `sinceSeq` (exclusive) forward — the
|
|
262
|
+
* focus-recall read behind `cotal_inbox`. Returns the messages (NOT emitted — this is a pull,
|
|
263
|
+
* not a push into context) plus `dropped: true` when the channel's earliest *retained* message
|
|
264
|
+
* is already newer than the watermark, i.e. some ambient aged out of the per-subject window and
|
|
265
|
+
* the caller must say so rather than silently short the window.
|
|
266
|
+
*
|
|
267
|
+
* Honors the **same** per-channel replay gate as join-backfill ({@link joinPolicyFresh}): a
|
|
268
|
+
* `replay=off` channel returns nothing, so `focus` can't become a history bypass for a channel
|
|
269
|
+
* that denies replay to everyone else (chat is `allow_direct` with no broker-level ACL, so this
|
|
270
|
+
* app gate is the entire boundary).
|
|
271
|
+
*/
|
|
272
|
+
recallChannel(channel: string, sinceSeq: number): Promise<{
|
|
273
|
+
messages: CotalMessage[];
|
|
274
|
+
dropped: boolean;
|
|
275
|
+
}>;
|
|
276
|
+
/** Did focus recall on `subject` miss ambient that aged out past the watermark? Ambient is only
|
|
277
|
+
* ever discarded once a sender-subject reaches {@link MAX_MSGS_PER_SUBJECT} (`DiscardPolicy.Old`);
|
|
278
|
+
* below the cap nothing was evicted, so the window is complete — return false without crying
|
|
279
|
+
* wolf. At the cap, the surviving oldest seq decides: if it already postdates the watermark, the
|
|
280
|
+
* eviction reached into the "since you focused" window. (Avoids the false positive of comparing a
|
|
281
|
+
* per-subject oldest against the stream-global frontier, which fires on any other channel's
|
|
282
|
+
* traffic.) */
|
|
283
|
+
private channelDropped;
|
|
284
|
+
/** Sequence of the earliest message still retained on a channel subject (any sender), or
|
|
285
|
+
* undefined if nothing is retained. One 1-message Direct Get — used for the recall drop marker. */
|
|
286
|
+
private channelOldestSeq;
|
|
168
287
|
private publishPresence;
|
|
169
288
|
private startPresenceWatch;
|
|
289
|
+
/** Watch the channel registry: replay existing keys, then stream updates, into the local
|
|
290
|
+
* cache. Best-effort — a registry the endpoint can't read leaves the cache empty (effective
|
|
291
|
+
* policy then falls back to the default), never a fault. */
|
|
292
|
+
private startChannelWatch;
|
|
293
|
+
private handleChannelEntry;
|
|
170
294
|
private handleKvEntry;
|
|
171
295
|
private applyPresence;
|
|
172
296
|
/** Mark a known peer offline (on KV delete/purge), keeping it in the roster. */
|
package/dist/endpoint.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"endpoint.d.ts","sourceRoot":"","sources":["../src/endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"endpoint.d.ts","sourceRoot":"","sources":["../src/endpoint.ts"],"names":[],"mappings":"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"}
|