@segmentstream/agent 0.1.1 → 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 flat layout, a package of its own like
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
- ├── agent.ts # model, reasoning, limits
29
- ├── instructions.md # who the company is, how the agent behaves
30
- └── extensions/
31
- └── segmentstream.ts # mounts this package with segmentstream.json
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 "../segmentstream.json";
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 link to `/agent/connect?code=…`, valid for ten minutes. In a
126
- group, the agent only asks an unknown sender to message it privately, because anyone in the group
127
- could open a link posted there. A revoked pairing or an inactive member gets a short refusal.
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 link.
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 who you are yet. Open this link and sign in to connect your Telegram account; it works for ten minutes:";
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 `I don't know who you are yet. Message me privately to connect your account.${bot?.username === void 0 ? "" : ` https://t.me/${bot.username}`}`;
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(`${UNKNOWN_PRIVATE}\n${dependencies.connectUrl(pairing.code)}`);
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.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",