@segmentstream/agent 0.1.0 → 0.1.2
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
CHANGED
|
@@ -18,31 +18,32 @@ npm install @segmentstream/agent eve@0.76.3
|
|
|
18
18
|
|
|
19
19
|
## Set up
|
|
20
20
|
|
|
21
|
-
The workspace's `agent/` directory is an eve app in eve's
|
|
22
|
-
`ontology/`:
|
|
21
|
+
The workspace's `agent/` directory is an eve app in eve's documented layout, a package of its own
|
|
22
|
+
like `ontology/`: the package files at the root, the authored files under `agent/agent/`:
|
|
23
23
|
|
|
24
24
|
```text
|
|
25
25
|
agent/
|
|
26
26
|
├── package.json # eve and @segmentstream/agent, both pinned; "build": "eve build"
|
|
27
27
|
├── segmentstream.json # what the extension mounts, and what the platform reads at deploy
|
|
28
|
-
|
|
29
|
-
├──
|
|
30
|
-
|
|
31
|
-
└──
|
|
28
|
+
└── agent/ # eve's agent directory
|
|
29
|
+
├── agent.ts # model, reasoning, limits
|
|
30
|
+
├── instructions.md # who the company is, how the agent behaves
|
|
31
|
+
└── extensions/
|
|
32
|
+
└── segmentstream.ts # mounts this package with segmentstream.json
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
**`extensions/segmentstream.ts`** mounts the extension. The file name is the mount's namespace, so
|
|
35
|
+
**`agent/agent/extensions/segmentstream.ts`** mounts the extension. The file name is the mount's namespace, so
|
|
35
36
|
every contribution is named `segmentstream__…`:
|
|
36
37
|
|
|
37
38
|
```ts
|
|
38
39
|
import { segmentstream } from "@segmentstream/agent/extension";
|
|
39
40
|
|
|
40
|
-
import config from "
|
|
41
|
+
import config from "../../segmentstream.json";
|
|
41
42
|
|
|
42
43
|
export default segmentstream(config);
|
|
43
44
|
```
|
|
44
45
|
|
|
45
|
-
**`agent.ts`** chooses the model once per session:
|
|
46
|
+
**`agent/agent/agent.ts`** chooses the model once per session:
|
|
46
47
|
|
|
47
48
|
```ts
|
|
48
49
|
import { defineAgent } from "eve";
|
|
@@ -122,9 +123,10 @@ share a group chat's session never share a client.
|
|
|
122
123
|
preview never answers a real chat. Without `channels.telegram` it answers 404.
|
|
123
124
|
- **Pairing.** Messages from bots and channel posts are dropped. The sender's Telegram account is
|
|
124
125
|
looked up with the ontology service on every message, so a revocation stops at once. An unknown
|
|
125
|
-
sender who writes privately gets a
|
|
126
|
-
group, the agent only asks an unknown sender to
|
|
127
|
-
|
|
126
|
+
sender who writes privately gets a message with a **Connect account** button that opens
|
|
127
|
+
`/agent/connect?code=…`, valid for ten minutes. In a group, the agent only asks an unknown sender to
|
|
128
|
+
message it privately, with a button to the bot's chat, because anyone in the group could open a
|
|
129
|
+
pairing link posted there. A revoked pairing or an inactive member gets a short refusal.
|
|
128
130
|
- **Who the agent is.** A paired sender's turn runs with the principal id `telegram:<user>`
|
|
129
131
|
(`telegram:<chat>:<user>` in groups) and the attributes `memberId`, `memberName`, `roles`,
|
|
130
132
|
`chatId`, `chatType` and `username`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The extension's configuration: `agent/segmentstream.json`, mounted by
|
|
3
|
-
* `agent/extensions/segmentstream.ts` and read by the platform at deploy.
|
|
3
|
+
* `agent/agent/extensions/segmentstream.ts` and read by the platform at deploy.
|
|
4
4
|
*
|
|
5
5
|
* eve validates a mount's configuration with a Standard Schema. The schema below is written by
|
|
6
6
|
* hand, so the package adds no second schema library next to the Effect Schema the rest of the
|
|
@@ -10,7 +10,7 @@ import { type Transcriber } from "./voice.js";
|
|
|
10
10
|
* eve's Telegram `onMessage` hook, in the order `agent-design.md` gives:
|
|
11
11
|
*
|
|
12
12
|
* 1. The hard gate, with no model: bots, channel posts and senders without a live pairing never
|
|
13
|
-
* start a turn. An unknown sender who writes to the bot privately gets a pairing
|
|
13
|
+
* start a turn. An unknown sender who writes to the bot privately gets a pairing button.
|
|
14
14
|
* 2. Voice becomes text, so the router and the agent read what was said.
|
|
15
15
|
* 3. The router answers or observes. An observed message goes to the chat's ring and stops here.
|
|
16
16
|
* 4. An answered message dispatches as the paired member, with the ring ahead of it as context.
|
|
@@ -8,8 +8,15 @@ import { telegramPrincipal } from "./principal.mjs";
|
|
|
8
8
|
import { observedChatKey, observedContext } from "./observed.mjs";
|
|
9
9
|
import { isAddressed, routeMessage } from "./router.mjs";
|
|
10
10
|
import { voiceNote, voiceOf, voiceText } from "./voice.mjs";
|
|
11
|
-
const UNKNOWN_PRIVATE = "I don't know
|
|
11
|
+
const UNKNOWN_PRIVATE = "Hi, I don't know you yet. Connect your Telegram account to the workspace and I'll act as you. The button works for ten minutes.";
|
|
12
|
+
const UNKNOWN_IN_GROUP = "I don't know you yet. Message me privately to connect your account.";
|
|
12
13
|
const REFUSED = "Your access to this agent was revoked, or your membership is inactive. Ask a workspace administrator.";
|
|
14
|
+
function buttonTo(text, url) {
|
|
15
|
+
return { inline_keyboard: [[{
|
|
16
|
+
text,
|
|
17
|
+
url
|
|
18
|
+
}]] };
|
|
19
|
+
}
|
|
13
20
|
function display(user) {
|
|
14
21
|
if (user.username !== void 0) return `@${user.username}`;
|
|
15
22
|
const name = [user.firstName, user.lastName].filter((part) => part !== void 0 && part !== "").join(" ");
|
|
@@ -27,7 +34,10 @@ function observedMessage(message, text) {
|
|
|
27
34
|
};
|
|
28
35
|
}
|
|
29
36
|
function unknownInGroup(bot) {
|
|
30
|
-
return
|
|
37
|
+
return bot?.username === void 0 ? { text: UNKNOWN_IN_GROUP } : {
|
|
38
|
+
text: UNKNOWN_IN_GROUP,
|
|
39
|
+
reply_markup: buttonTo("Message me", `https://t.me/${bot.username}`)
|
|
40
|
+
};
|
|
31
41
|
}
|
|
32
42
|
async function answerUnpaired(input) {
|
|
33
43
|
const { context, message, lookup, dependencies } = input;
|
|
@@ -45,7 +55,10 @@ async function answerUnpaired(input) {
|
|
|
45
55
|
externalId: message.from.id,
|
|
46
56
|
...sender === void 0 ? {} : { display: sender }
|
|
47
57
|
});
|
|
48
|
-
await context.telegram.post(
|
|
58
|
+
await context.telegram.post({
|
|
59
|
+
text: UNKNOWN_PRIVATE,
|
|
60
|
+
reply_markup: buttonTo("Connect account", dependencies.connectUrl(pairing.code))
|
|
61
|
+
});
|
|
49
62
|
}
|
|
50
63
|
async function handleInboundMessage(input) {
|
|
51
64
|
const { context, dependencies } = input;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@segmentstream/agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Mount a SegmentStream workspace's agent on eve: the ontology as tools, acting as the member who writes, and Telegram through the workspace's connection.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "SegmentStream",
|