@acedatacloud/skills 2026.620.0 → 2026.621.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/package.json +1 -1
- package/skills/cos-upload/SKILL.md +41 -0
- package/skills/fish-audio/SKILL.md +35 -51
- package/skills/gpt-image-2/SKILL.md +64 -0
- package/skills/telegram/SKILL.md +195 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acedatacloud/skills",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.621.0",
|
|
4
4
|
"description": "Agent Skills for AceDataCloud AI services — music, image, video generation, LLM chat, web search. Compatible with Claude Code, GitHub Copilot, Gemini CLI, OpenAI Codex, and 30+ AI coding agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skills",
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cos-upload
|
|
3
|
+
description: Upload a local file to AceData Cloud CDN and get back a public URL. Use whenever you produce a local artifact (image, audio, video, doc) that another API needs as a URL, or that you need to return/persist (e.g. feed a generated image into an image-to-video API, or publish a finished video).
|
|
4
|
+
license: Apache-2.0
|
|
5
|
+
metadata:
|
|
6
|
+
author: acedatacloud
|
|
7
|
+
version: "1.0"
|
|
8
|
+
compatibility: Requires ACEDATACLOUD_PLATFORM_TOKEN (see _shared/authentication.md). Some runtimes instead provide a bundled uploader — prefer that when present.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Upload a file → AceData CDN URL
|
|
12
|
+
|
|
13
|
+
Turn a local file into a public `https://cdn.acedata.cloud/...` URL.
|
|
14
|
+
|
|
15
|
+
## Upload (multipart, synchronous)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
curl -s -X POST https://platform.acedata.cloud/api/v1/files/ \
|
|
19
|
+
-H "Authorization: Bearer $ACEDATACLOUD_PLATFORM_TOKEN" \
|
|
20
|
+
-F "file=@/path/to/video.mp4"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Response:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{"file_url": "https://cdn.acedata.cloud/7f849b80b9.mp4"}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
→ use `file_url`. One file per request (loop for several).
|
|
30
|
+
|
|
31
|
+
## When to use
|
|
32
|
+
|
|
33
|
+
- **Feed a generated asset into another API by URL** — e.g. upload a gpt-image-2 still, then pass its URL to `seedance` / `kling` image-to-video.
|
|
34
|
+
- **Publish/return a finished artifact** (final video, cover image).
|
|
35
|
+
- **Persist intermediate artifacts** so a later run can re-download and continue.
|
|
36
|
+
|
|
37
|
+
## Notes
|
|
38
|
+
|
|
39
|
+
- Auth uses the **platform token** (`ACEDATACLOUD_PLATFORM_TOKEN`), not the per-service API token — the files endpoint is on `platform.acedata.cloud`, not `api.acedata.cloud`.
|
|
40
|
+
- If your runtime ships a bundled uploader (e.g. a worker that owns the storage creds), prefer it — it avoids handling the platform token directly.
|
|
41
|
+
- The returned URL is CDN-served and stable; safe to store and re-download later.
|
|
@@ -1,99 +1,83 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fish-audio
|
|
3
|
-
description: Generate AI audio and
|
|
3
|
+
description: Generate AI text-to-speech audio and clone voices with Fish Audio via AceDataCloud API. Use when creating voiceover/narration audio (TTS), synthesizing speech, or cloning a reference voice. Chinese + multilingual.
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: acedatacloud
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.1"
|
|
8
8
|
compatibility: Requires ACEDATACLOUD_API_TOKEN in .env file (see _shared/authentication.md).
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
# Fish Audio —
|
|
11
|
+
# Fish Audio — Text-to-Speech & Voice Cloning
|
|
12
12
|
|
|
13
|
-
Generate
|
|
13
|
+
Generate narration / voiceover and clone voices through AceDataCloud's Fish Audio API.
|
|
14
14
|
|
|
15
15
|
> **Setup:** See [authentication](../_shared/authentication.md) for token setup.
|
|
16
16
|
|
|
17
|
-
## Quick Start
|
|
17
|
+
## Quick Start (TTS — synchronous, ~3s)
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
curl -X POST https://api.acedata.cloud/fish/audios \
|
|
21
21
|
-H "Authorization: Bearer $ACEDATACLOUD_API_TOKEN" \
|
|
22
22
|
-H "Content-Type: application/json" \
|
|
23
|
-
-d '{"prompt":
|
|
23
|
+
-d '{"action":"speech","model":"fish-tts","voice_id":"543e4181d81b4ef6874b0e8fbdf27c78","prompt":"你好,欢迎使用 AceData Cloud。"}'
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Response (synchronous — no polling needed for `speech`):
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{"success": true, "data": [{"audio_url": "https://platform.r2.fish.audio/task/....mp3"}]}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
→ download `data[0].audio_url`. `voice_id` is **required**. A good default Mandarin
|
|
33
|
+
news-anchor voice is **`543e4181d81b4ef6874b0e8fbdf27c78`**.
|
|
27
34
|
|
|
28
35
|
## Endpoints
|
|
29
36
|
|
|
30
37
|
| Endpoint | Purpose |
|
|
31
38
|
|----------|---------|
|
|
32
|
-
| `POST /fish/audios` |
|
|
33
|
-
| `POST /fish/voices` |
|
|
34
|
-
| `POST /fish/tasks` | Poll task status |
|
|
39
|
+
| `POST /fish/audios` | TTS (`action: "speech"`) — synchronous |
|
|
40
|
+
| `POST /fish/voices` | List / register (clone) voices |
|
|
35
41
|
|
|
36
42
|
## Workflows
|
|
37
43
|
|
|
38
|
-
### 1. Text-to-Speech
|
|
44
|
+
### 1. Text-to-Speech (the common case)
|
|
39
45
|
|
|
40
46
|
```json
|
|
41
47
|
POST /fish/audios
|
|
42
48
|
{
|
|
43
|
-
"
|
|
44
|
-
"
|
|
49
|
+
"action": "speech",
|
|
50
|
+
"model": "fish-tts",
|
|
51
|
+
"voice_id": "543e4181d81b4ef6874b0e8fbdf27c78",
|
|
52
|
+
"prompt": "你的旁白文本。"
|
|
45
53
|
}
|
|
46
54
|
```
|
|
47
55
|
|
|
48
|
-
### 2.
|
|
49
|
-
|
|
50
|
-
Upload a reference audio to create a cloneable voice.
|
|
56
|
+
### 2. Clone a voice from a reference sample
|
|
51
57
|
|
|
52
58
|
```json
|
|
53
59
|
POST /fish/voices
|
|
54
60
|
{
|
|
55
61
|
"voice_url": "https://example.com/reference-voice.mp3",
|
|
56
62
|
"title": "My Custom Voice",
|
|
57
|
-
"description": "Clear, neutral-toned speaker
|
|
58
|
-
"image_url": "https://example.com/avatar.jpg"
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### 3. Text-to-Speech with Cloned Voice
|
|
63
|
-
|
|
64
|
-
```json
|
|
65
|
-
POST /fish/audios
|
|
66
|
-
{
|
|
67
|
-
"prompt": "Welcome to our platform.",
|
|
68
|
-
"voice_id": "<voice_id from POST /fish/voices>"
|
|
63
|
+
"description": "Clear, neutral-toned speaker"
|
|
69
64
|
}
|
|
70
65
|
```
|
|
71
66
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
### `/fish/audios`
|
|
75
|
-
|
|
76
|
-
| Parameter | Type | Description |
|
|
77
|
-
|-----------|------|-------------|
|
|
78
|
-
| `prompt` | string | Text to synthesize into speech |
|
|
79
|
-
| `voice_id` | string | Voice model or cloned voice ID to use |
|
|
80
|
-
| `model` | string | TTS model (e.g., `"speech-1.5"`, `"speech-1.5-hd"`) |
|
|
81
|
-
| `action` | string | Operation type (e.g., `"generate"`) |
|
|
82
|
-
| `callback_url` | string | Webhook URL for async delivery |
|
|
67
|
+
Then pass the returned id as `voice_id` in workflow 1.
|
|
83
68
|
|
|
84
|
-
|
|
69
|
+
## Parameters — `/fish/audios`
|
|
85
70
|
|
|
86
|
-
| Parameter | Type | Description |
|
|
87
|
-
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
92
|
-
| `callback_url` | string | Webhook URL for async delivery |
|
|
71
|
+
| Parameter | Type | Required | Description |
|
|
72
|
+
|-----------|------|----------|-------------|
|
|
73
|
+
| `action` | string | yes | Use `"speech"` for TTS |
|
|
74
|
+
| `model` | string | yes | `"fish-tts"` |
|
|
75
|
+
| `voice_id` | string | yes | A Fish reference/cloned voice id (default Mandarin: `543e4181d81b4ef6874b0e8fbdf27c78`) |
|
|
76
|
+
| `prompt` | string | yes | Text to synthesize |
|
|
93
77
|
|
|
94
78
|
## Gotchas
|
|
95
79
|
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
80
|
+
- **TTS (`action:"speech"`) is synchronous** — the response carries `data[0].audio_url`; do NOT poll `/fish/tasks` for it.
|
|
81
|
+
- `voice_id` is **required** — a bare `{"prompt": "..."}` returns `400 voice_id is required when action is speech`.
|
|
82
|
+
- `model` must be `"fish-tts"` for speech (NOT `speech-1.5`); sending a different model returns `400 model is invalid if action is speech`.
|
|
83
|
+
- Pricing is based on the **byte count** of the generated audio. Multilingual is automatic.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gpt-image-2
|
|
3
|
+
description: Generate and EDIT images with OpenAI gpt-image-2 via AceDataCloud API. Use when you need high-fidelity images from a prompt, or to edit/composite existing images (e.g. fuse a real logo/QR/screenshot into a scene, keep characters consistent, restyle). Strong at legible text and faithful editing.
|
|
4
|
+
license: Apache-2.0
|
|
5
|
+
metadata:
|
|
6
|
+
author: acedatacloud
|
|
7
|
+
version: "1.0"
|
|
8
|
+
compatibility: Requires ACEDATACLOUD_API_TOKEN in .env file (see _shared/authentication.md).
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# gpt-image-2 — Image Generation & Editing
|
|
12
|
+
|
|
13
|
+
OpenAI `gpt-image-2` through AceDataCloud. Two endpoints, both **synchronous** (return image url(s) directly). Its standout is **editing**: feed real images (logos, QR codes, product shots, screenshots) and it composites/restyles them faithfully — great for on-brand video assets and character consistency.
|
|
14
|
+
|
|
15
|
+
> **Setup:** See [authentication](../_shared/authentication.md) for token setup.
|
|
16
|
+
|
|
17
|
+
## 1. Generate (text → image)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
curl -X POST https://api.acedata.cloud/openai/images/generations \
|
|
21
|
+
-H "Authorization: Bearer $ACEDATACLOUD_API_TOKEN" \
|
|
22
|
+
-H "Content-Type: application/json" \
|
|
23
|
+
-d '{"model":"gpt-image-2","prompt":"a clean dark tech hero background with a glowing API hub, lots of negative space","size":"1792x1024","n":1}'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 2. Edit / composite (images + prompt → image) ← the powerful one
|
|
27
|
+
|
|
28
|
+
Multipart. Pass one or more source images via repeated `image[]` (local files with
|
|
29
|
+
`@`, or URLs). Use it to **fuse a real logo/QR into a generated scene**, keep a subject
|
|
30
|
+
consistent across scenes, or restyle a screenshot.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
curl -X POST https://api.acedata.cloud/openai/images/edits \
|
|
34
|
+
-H "Authorization: Bearer $ACEDATACLOUD_API_TOKEN" \
|
|
35
|
+
-F "model=gpt-image-2" \
|
|
36
|
+
-F "prompt=Place this logo crisply in the top-left on the tech background; keep the logo's exact colors and shape." \
|
|
37
|
+
-F "image[]=@background.png" \
|
|
38
|
+
-F "image[]=@logo.png" \
|
|
39
|
+
-F "size=1792x1024" \
|
|
40
|
+
-F "n=1"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Response (both endpoints): `{"data":[{"url":"https://...png"}]}` → download `data[0].url`.
|
|
44
|
+
|
|
45
|
+
## Sizes
|
|
46
|
+
|
|
47
|
+
`size` is `WxH` (a preset) or `"auto"`. Common presets:
|
|
48
|
+
|
|
49
|
+
| Aspect | Sizes |
|
|
50
|
+
|---|---|
|
|
51
|
+
| 16:9 | `1792x1024` (HD), `2048x1152`, `3840x2160` (4K) |
|
|
52
|
+
| 9:16 | `1024x1792`, `1152x2048`, `2160x3840` |
|
|
53
|
+
| 1:1 | `1024x1024`, `2048x2048`, `4096x4096` |
|
|
54
|
+
|
|
55
|
+
(Omit `size` or use `"auto"` to let the model pick. Invalid sizes 400.)
|
|
56
|
+
|
|
57
|
+
## Tips
|
|
58
|
+
|
|
59
|
+
- **Editing keeps things faithful** — to place a logo/QR exactly, pass it as one of the
|
|
60
|
+
`image[]` and say "keep its exact colors/shape, do not redraw it".
|
|
61
|
+
- For **character/scene consistency** across video beats, generate one hero image, then
|
|
62
|
+
`edits` it per beat instead of regenerating from scratch.
|
|
63
|
+
- Text in images renders legibly — good for titles/labels you don't want to overlay in HTML.
|
|
64
|
+
- Both endpoints are synchronous; no `/tasks` polling.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: telegram
|
|
3
|
+
description: Read, search and send personal Telegram messages — list recent chats / contacts / groups, pull a conversation's history, search messages, and send a message — driven by the Telethon MTProto client with the user's own account. Use when the user mentions Telegram, a Telegram chat/group/contact, "我的 Telegram", reading or replying to Telegram messages, or summarizing Telegram conversations.
|
|
4
|
+
when_to_use: |
|
|
5
|
+
Trigger when the user wants to do anything with their personal Telegram
|
|
6
|
+
account: list recent conversations, read / summarize the history of a chat
|
|
7
|
+
or group, search their messages for a keyword, look up a contact, or send /
|
|
8
|
+
reply to a message. This drives the user's OWN account over MTProto (not a
|
|
9
|
+
bot), so it can see everything the user can see.
|
|
10
|
+
connections: [telegram]
|
|
11
|
+
allowed_tools: [Bash]
|
|
12
|
+
license: Apache-2.0
|
|
13
|
+
metadata:
|
|
14
|
+
author: acedatacloud
|
|
15
|
+
version: "1.0"
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
We drive **personal** Telegram over the MTProto protocol with the
|
|
19
|
+
[Telethon](https://docs.telethon.dev/) Python library — this acts as the user's own
|
|
20
|
+
account (a "userbot"), so unlike the Bot API it can read full chat history, list every
|
|
21
|
+
conversation, and message anyone the user can message.
|
|
22
|
+
|
|
23
|
+
The user's credentials are injected as environment variables by the connector:
|
|
24
|
+
|
|
25
|
+
- `TELEGRAM_API_ID` — the app id (from my.telegram.org)
|
|
26
|
+
- `TELEGRAM_API_HASH` — the app hash — **secret, never echo it**
|
|
27
|
+
- `TELEGRAM_SESSION_STRING` — a Telethon `StringSession` = **full account access. Never log,
|
|
28
|
+
echo, or print it.** Treat it like the account password.
|
|
29
|
+
|
|
30
|
+
## Setup — write the helper once per session
|
|
31
|
+
|
|
32
|
+
`telethon` is preinstalled in the sandbox image. The helper is written to `./tg.py` **in the
|
|
33
|
+
current working directory** (the per-session workdir) — not a shared global path like `/tmp` —
|
|
34
|
+
so concurrent sessions never race on or reuse each other's file.
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
# telethon is preinstalled; the `|| pip install` is a best-effort fallback only
|
|
38
|
+
# (the sandbox is non-root, so a runtime install may not succeed — rely on the
|
|
39
|
+
# preinstalled package).
|
|
40
|
+
python3 -c "import telethon" 2>/dev/null || pip install --user --quiet telethon 2>/dev/null || true
|
|
41
|
+
|
|
42
|
+
cat > ./tg.py <<'PY'
|
|
43
|
+
import os, sys, json, asyncio
|
|
44
|
+
from telethon import TelegramClient
|
|
45
|
+
from telethon.sessions import StringSession
|
|
46
|
+
|
|
47
|
+
API_ID = int(os.environ["TELEGRAM_API_ID"])
|
|
48
|
+
API_HASH = os.environ["TELEGRAM_API_HASH"]
|
|
49
|
+
SESSION = os.environ["TELEGRAM_SESSION_STRING"]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
async def resolve(client, target):
|
|
53
|
+
# Accept a numeric id, @username, phone, or an exact chat display name.
|
|
54
|
+
try:
|
|
55
|
+
return await client.get_entity(int(target))
|
|
56
|
+
except (ValueError, TypeError):
|
|
57
|
+
pass
|
|
58
|
+
try:
|
|
59
|
+
return await client.get_entity(target)
|
|
60
|
+
except Exception:
|
|
61
|
+
async for d in client.iter_dialogs():
|
|
62
|
+
if d.name == target:
|
|
63
|
+
return d.entity
|
|
64
|
+
raise ValueError(f"could not resolve target: {target}")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
async def main():
|
|
68
|
+
cmd = sys.argv[1]
|
|
69
|
+
async with TelegramClient(StringSession(SESSION), API_ID, API_HASH) as client:
|
|
70
|
+
if cmd == "whoami":
|
|
71
|
+
me = await client.get_me()
|
|
72
|
+
print(json.dumps({"id": me.id, "username": me.username,
|
|
73
|
+
"name": ((me.first_name or "") + " " + (me.last_name or "")).strip()},
|
|
74
|
+
ensure_ascii=False))
|
|
75
|
+
elif cmd == "list-chats":
|
|
76
|
+
limit = int(sys.argv[2]) if len(sys.argv) > 2 else 20
|
|
77
|
+
out = []
|
|
78
|
+
async for d in client.iter_dialogs(limit=limit):
|
|
79
|
+
out.append({"name": d.name, "id": d.id, "group": d.is_group,
|
|
80
|
+
"channel": d.is_channel, "user": d.is_user, "unread": d.unread_count})
|
|
81
|
+
print(json.dumps(out, ensure_ascii=False))
|
|
82
|
+
elif cmd == "get-messages":
|
|
83
|
+
target = sys.argv[2]
|
|
84
|
+
n = int(sys.argv[3]) if len(sys.argv) > 3 else 50
|
|
85
|
+
ent = await resolve(client, target)
|
|
86
|
+
out = []
|
|
87
|
+
async for m in client.iter_messages(ent, limit=n):
|
|
88
|
+
out.append({"id": m.id, "date": str(m.date), "out": m.out,
|
|
89
|
+
"sender_id": m.sender_id, "text": m.message})
|
|
90
|
+
out.reverse()
|
|
91
|
+
print(json.dumps(out, ensure_ascii=False))
|
|
92
|
+
elif cmd == "search":
|
|
93
|
+
target, query = sys.argv[2], sys.argv[3]
|
|
94
|
+
n = int(sys.argv[4]) if len(sys.argv) > 4 else 30
|
|
95
|
+
ent = await resolve(client, target)
|
|
96
|
+
out = []
|
|
97
|
+
async for m in client.iter_messages(ent, search=query, limit=n):
|
|
98
|
+
out.append({"id": m.id, "date": str(m.date), "sender_id": m.sender_id, "text": m.message})
|
|
99
|
+
print(json.dumps(out, ensure_ascii=False))
|
|
100
|
+
elif cmd == "send":
|
|
101
|
+
# Gated: without --confirm this only DRY-RUNS (prints the intended
|
|
102
|
+
# target + text and sends nothing). Pass --confirm to actually send.
|
|
103
|
+
target, text = sys.argv[2], sys.argv[3]
|
|
104
|
+
confirm = "--confirm" in sys.argv[4:]
|
|
105
|
+
ent = await resolve(client, target)
|
|
106
|
+
if not confirm:
|
|
107
|
+
name = getattr(ent, "title", None) or getattr(ent, "first_name", None) or str(target)
|
|
108
|
+
print(json.dumps({"dry_run": True, "would_send_to": name, "text": text,
|
|
109
|
+
"note": "re-run with --confirm to actually send"}, ensure_ascii=False))
|
|
110
|
+
return
|
|
111
|
+
msg = await client.send_message(ent, text)
|
|
112
|
+
print(json.dumps({"sent": True, "id": msg.id}, ensure_ascii=False))
|
|
113
|
+
else:
|
|
114
|
+
print(json.dumps({"error": f"unknown command: {cmd}"}))
|
|
115
|
+
sys.exit(1)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
asyncio.run(main())
|
|
119
|
+
PY
|
|
120
|
+
echo "helper ready"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Verify the connection (run this first)
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
python3 ./tg.py whoami
|
|
127
|
+
# → {"id": 8367450178, "username": "GermeyAce", "name": "Germey"}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
If this errors with an auth/session message, the stored session is dead (revoked or expired) —
|
|
131
|
+
tell the user to reconnect the Telegram connector at https://auth.acedata.cloud/user/connections.
|
|
132
|
+
|
|
133
|
+
## Recipes
|
|
134
|
+
|
|
135
|
+
### List recent conversations
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
python3 ./tg.py list-chats 20
|
|
139
|
+
# → [{"name":"Ace <> ConduitOS","id":-5287630726,"group":true,...,"unread":0}, ...]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Use the returned `id` (or the exact `name`) as the target for the next calls.
|
|
143
|
+
|
|
144
|
+
### Read a conversation's history (oldest→newest)
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
# target = numeric id, @username, phone, or exact chat name; second arg = how many messages
|
|
148
|
+
python3 ./tg.py get-messages -5287630726 50
|
|
149
|
+
python3 ./tg.py get-messages @some_username 30
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`out: true` means the message was sent BY the user; `sender_id` is the author. Summarize from
|
|
153
|
+
the returned JSON.
|
|
154
|
+
|
|
155
|
+
### Search inside a conversation
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
python3 ./tg.py search -5287630726 "keyword" 30
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
(Server-side search is scoped to one chat. To search broadly, list chats first, then search the
|
|
162
|
+
relevant ones.)
|
|
163
|
+
|
|
164
|
+
### Send / reply to a message — TWO-STEP, confirm first
|
|
165
|
+
|
|
166
|
+
Sending posts a **real message as the user**, so it is gated:
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
# Step 1 — DRY RUN (default, sends nothing). Show this preview to the user.
|
|
170
|
+
python3 ./tg.py send -5287630726 "Hi, following up on this."
|
|
171
|
+
# → {"dry_run": true, "would_send_to": "Ace <> ConduitOS", "text": "Hi, following up on this.", ...}
|
|
172
|
+
|
|
173
|
+
# Step 2 — only after the user explicitly says yes in the conversation, add --confirm:
|
|
174
|
+
python3 ./tg.py send -5287630726 "Hi, following up on this." --confirm
|
|
175
|
+
# → {"sent": true, "id": 4502}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Always run the dry run first, show the user exactly who + what, and require an explicit "yes"
|
|
179
|
+
before re-running with `--confirm`** — even if the original instruction said "just send it".
|
|
180
|
+
Never bulk-send.
|
|
181
|
+
|
|
182
|
+
## Gotchas — surface these before the user is surprised
|
|
183
|
+
|
|
184
|
+
- **This is the user's real account.** Sending posts as them; reading exposes all their private
|
|
185
|
+
chats. Be conservative.
|
|
186
|
+
- **`FloodWaitError`**: Telegram rate-limits userbots. If a call fails with a flood-wait of N
|
|
187
|
+
seconds, tell the user to retry after N seconds — do not loop/retry aggressively (it escalates
|
|
188
|
+
toward an account ban).
|
|
189
|
+
- **Dead session**: a `session_string` can be revoked by the user from Telegram → Settings →
|
|
190
|
+
Devices. On an `AuthKeyError` / unauthorized error, the fix is reconnecting the connector, not
|
|
191
|
+
retrying.
|
|
192
|
+
- **Never print `TELEGRAM_SESSION_STRING` or `TELEGRAM_API_HASH`** — they are full-account
|
|
193
|
+
secrets. The helper never prints them; keep it that way.
|
|
194
|
+
- **Resolving targets**: prefer the numeric `id` from `list-chats` (most reliable). Names work
|
|
195
|
+
only on an exact match; usernames need the leading `@`.
|