personagent 1.0.0__tar.gz
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.
- personagent-1.0.0/.env.example +423 -0
- personagent-1.0.0/LICENSE +21 -0
- personagent-1.0.0/MANIFEST.in +7 -0
- personagent-1.0.0/PKG-INFO +469 -0
- personagent-1.0.0/README.md +425 -0
- personagent-1.0.0/data/benchmark/scenarios.holdout.en.jsonl +26 -0
- personagent-1.0.0/data/benchmark/scenarios.train.en.jsonl +38 -0
- personagent-1.0.0/data/evals/learning.en.jsonl +10 -0
- personagent-1.0.0/data/evals/learning.zh.jsonl +10 -0
- personagent-1.0.0/data/evals/persona.en.jsonl +18 -0
- personagent-1.0.0/data/evals/persona.zh.jsonl +18 -0
- personagent-1.0.0/data/evals/speak.en.jsonl +24 -0
- personagent-1.0.0/data/evals/speak.zh.jsonl +24 -0
- personagent-1.0.0/data/examples.en.jsonl +5 -0
- personagent-1.0.0/data/examples.zh.jsonl +5 -0
- personagent-1.0.0/data/feedback.en.jsonl +5 -0
- personagent-1.0.0/data/feedback.zh.jsonl +5 -0
- personagent-1.0.0/data/lorebook.en.json +47 -0
- personagent-1.0.0/data/lorebook.zh.json +53 -0
- personagent-1.0.0/data/output_filter.en.json +71 -0
- personagent-1.0.0/data/output_filter.zh.json +77 -0
- personagent-1.0.0/data/persona.example.en.txt +13 -0
- personagent-1.0.0/data/persona.example.zh.txt +13 -0
- personagent-1.0.0/data/personas/en/bookworm.txt +8 -0
- personagent-1.0.0/data/personas/en/dry-wit.txt +9 -0
- personagent-1.0.0/data/personas/en/gamer.txt +8 -0
- personagent-1.0.0/data/personas/en/warm-listener.txt +10 -0
- personagent-1.0.0/data/personas/zh/bookworm.txt +8 -0
- personagent-1.0.0/data/personas/zh/dry-wit.txt +9 -0
- personagent-1.0.0/data/personas/zh/gamer.txt +8 -0
- personagent-1.0.0/data/personas/zh/warm-listener.txt +10 -0
- personagent-1.0.0/integrations/astrbot/astrbot_plugin_personagent/LICENSE +21 -0
- personagent-1.0.0/integrations/astrbot/astrbot_plugin_personagent/README.md +361 -0
- personagent-1.0.0/integrations/astrbot/astrbot_plugin_personagent/README.zh-CN.md +98 -0
- personagent-1.0.0/integrations/astrbot/astrbot_plugin_personagent/_conf_schema.json +67 -0
- personagent-1.0.0/integrations/astrbot/astrbot_plugin_personagent/logo.png +0 -0
- personagent-1.0.0/integrations/astrbot/astrbot_plugin_personagent/main.py +1480 -0
- personagent-1.0.0/integrations/astrbot/astrbot_plugin_personagent/metadata.yaml +35 -0
- personagent-1.0.0/integrations/astrbot/astrbot_plugin_personagent/personagent_connector.py +204 -0
- personagent-1.0.0/integrations/astrbot/astrbot_plugin_personagent/platforms.py +332 -0
- personagent-1.0.0/integrations/astrbot/astrbot_plugin_personagent/requirements.txt +1 -0
- personagent-1.0.0/persona_agent/__init__.py +46 -0
- personagent-1.0.0/persona_agent/__main__.py +3 -0
- personagent-1.0.0/persona_agent/access.py +195 -0
- personagent-1.0.0/persona_agent/addressing.py +43 -0
- personagent-1.0.0/persona_agent/agent.py +729 -0
- personagent-1.0.0/persona_agent/candidates.py +526 -0
- personagent-1.0.0/persona_agent/channels.py +111 -0
- personagent-1.0.0/persona_agent/chat.py +1230 -0
- personagent-1.0.0/persona_agent/cli.py +119 -0
- personagent-1.0.0/persona_agent/config_env.py +149 -0
- personagent-1.0.0/persona_agent/connector.py +468 -0
- personagent-1.0.0/persona_agent/dashboard.py +997 -0
- personagent-1.0.0/persona_agent/decision.py +130 -0
- personagent-1.0.0/persona_agent/decision_log.py +94 -0
- personagent-1.0.0/persona_agent/demo.py +812 -0
- personagent-1.0.0/persona_agent/dm.py +290 -0
- personagent-1.0.0/persona_agent/doctor.py +144 -0
- personagent-1.0.0/persona_agent/embeddings.py +167 -0
- personagent-1.0.0/persona_agent/endpoints.py +129 -0
- personagent-1.0.0/persona_agent/evals.py +1101 -0
- personagent-1.0.0/persona_agent/evidence.py +484 -0
- personagent-1.0.0/persona_agent/evolution.py +327 -0
- personagent-1.0.0/persona_agent/health.py +300 -0
- personagent-1.0.0/persona_agent/home.py +69 -0
- personagent-1.0.0/persona_agent/ingestion.py +1579 -0
- personagent-1.0.0/persona_agent/learning.py +1045 -0
- personagent-1.0.0/persona_agent/ledger_admin.py +339 -0
- personagent-1.0.0/persona_agent/lineage.py +101 -0
- personagent-1.0.0/persona_agent/llm.py +700 -0
- personagent-1.0.0/persona_agent/memory.py +717 -0
- personagent-1.0.0/persona_agent/messages.py +254 -0
- personagent-1.0.0/persona_agent/outbox.py +494 -0
- personagent-1.0.0/persona_agent/paths.py +128 -0
- personagent-1.0.0/persona_agent/pools.py +130 -0
- personagent-1.0.0/persona_agent/preflight.py +565 -0
- personagent-1.0.0/persona_agent/proactive.py +207 -0
- personagent-1.0.0/persona_agent/promotion.py +602 -0
- personagent-1.0.0/persona_agent/prompt.py +582 -0
- personagent-1.0.0/persona_agent/prompts.py +1022 -0
- personagent-1.0.0/persona_agent/py.typed +0 -0
- personagent-1.0.0/persona_agent/ranking.py +117 -0
- personagent-1.0.0/persona_agent/reactions.py +754 -0
- personagent-1.0.0/persona_agent/retrieval.py +388 -0
- personagent-1.0.0/persona_agent/search.py +198 -0
- personagent-1.0.0/persona_agent/server.py +1214 -0
- personagent-1.0.0/persona_agent/settings.py +509 -0
- personagent-1.0.0/persona_agent/setup_wizard.py +1685 -0
- personagent-1.0.0/persona_agent/static/app.css +1239 -0
- personagent-1.0.0/persona_agent/static/app.js +1812 -0
- personagent-1.0.0/persona_agent/static/empty-chats.webp +0 -0
- personagent-1.0.0/persona_agent/static/index.html +47 -0
- personagent-1.0.0/persona_agent/static/learned-notebook.webp +0 -0
- personagent-1.0.0/persona_agent/static/listening.webp +0 -0
- personagent-1.0.0/persona_agent/static/mark.svg +19 -0
- personagent-1.0.0/persona_agent/stickers.py +692 -0
- personagent-1.0.0/persona_agent/storage.py +373 -0
- personagent-1.0.0/persona_agent/textproc.py +2904 -0
- personagent-1.0.0/persona_agent/thinking.py +77 -0
- personagent-1.0.0/persona_agent/transport.py +625 -0
- personagent-1.0.0/persona_agent/turns.py +627 -0
- personagent-1.0.0/persona_agent/views.py +498 -0
- personagent-1.0.0/personagent.egg-info/PKG-INFO +469 -0
- personagent-1.0.0/personagent.egg-info/SOURCES.txt +110 -0
- personagent-1.0.0/personagent.egg-info/dependency_links.txt +1 -0
- personagent-1.0.0/personagent.egg-info/entry_points.txt +2 -0
- personagent-1.0.0/personagent.egg-info/requires.txt +15 -0
- personagent-1.0.0/personagent.egg-info/top_level.txt +1 -0
- personagent-1.0.0/pyproject.toml +63 -0
- personagent-1.0.0/requirements.txt +13 -0
- personagent-1.0.0/setup.cfg +4 -0
- personagent-1.0.0/setup.py +43 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
# personagent settings. `personagent init` fills in the first block for you.
|
|
2
|
+
# Each setting is described on the lines above it; a blank value means the
|
|
3
|
+
# default the description gives.
|
|
4
|
+
|
|
5
|
+
# ============================================================================
|
|
6
|
+
# REQUIRED
|
|
7
|
+
# ============================================================================
|
|
8
|
+
|
|
9
|
+
# The chat model: any OpenAI-compatible service, hosted or local (Ollama).
|
|
10
|
+
# The key is all that `personagent chat` needs.
|
|
11
|
+
LLM_API_KEY=
|
|
12
|
+
# The API address as the provider documents it: a root such as
|
|
13
|
+
# https://api.deepseek.com, a version base such as .../v1 or .../api/paas/v4,
|
|
14
|
+
# or the full /chat/completions URL.
|
|
15
|
+
LLM_BASE_URL=https://api.deepseek.com
|
|
16
|
+
LLM_MODEL=deepseek-flash
|
|
17
|
+
|
|
18
|
+
# The bot's name. It notices being addressed when a message contains it.
|
|
19
|
+
PERSONA_NAME=
|
|
20
|
+
|
|
21
|
+
# Language of the agent: en or zh. Picks the bundled examples, feedback,
|
|
22
|
+
# lorebook and output filters (data/*.en.* or data/*.zh.*), the reply checks
|
|
23
|
+
# and the words its commands understand. It does not translate your persona.
|
|
24
|
+
AGENT_LANG=en
|
|
25
|
+
|
|
26
|
+
# ============================================================================
|
|
27
|
+
# PERSONA AND ACCESS
|
|
28
|
+
# ============================================================================
|
|
29
|
+
|
|
30
|
+
# The persona document, and its optional companion card, both relative to
|
|
31
|
+
# AGENT_HOME. Until persona.txt exists, the bundled
|
|
32
|
+
# data/persona.example.<lang>.txt stands in.
|
|
33
|
+
# The card holds per-persona reply-style opt-ins, such as
|
|
34
|
+
# {"reply_style": {"emoji": true, "charsets": ["music"], "max_chars": 320}};
|
|
35
|
+
# charsets are ellipsis, music and arrows. Without a card no emoji and no
|
|
36
|
+
# optional characters are allowed. A `[style]` block at the end of the persona
|
|
37
|
+
# document sets the six register knobs: length, vent, recs, good_news,
|
|
38
|
+
# particles and fatigue.
|
|
39
|
+
PERSONA_FILE=persona.txt
|
|
40
|
+
PERSONA_CARD_FILE=persona.card.json
|
|
41
|
+
|
|
42
|
+
# The persona's time zone as a UTC offset in hours, from -12 to 14, such as
|
|
43
|
+
# 8 or -5. It sets the time shown to the model and the 02:00-07:00 sleep
|
|
44
|
+
# window, when the bot does not start conversations. Blank = UTC+8 when
|
|
45
|
+
# AGENT_LANG is zh, this machine's offset otherwise.
|
|
46
|
+
PERSONA_TZ_OFFSET_HOURS=
|
|
47
|
+
|
|
48
|
+
# A label recorded on every evidence event beside a hash of the persona text.
|
|
49
|
+
# Editing the persona keeps what the bot learned: every version under one
|
|
50
|
+
# label counts as the same character (runtime/persona_lineage.json). Change
|
|
51
|
+
# the label to start a new character with a clean slate.
|
|
52
|
+
PERSONA_VERSION=
|
|
53
|
+
|
|
54
|
+
# Ids are written "<platform>:<id>", the platform spelled as the connector
|
|
55
|
+
# names it (AstrBot's adapter names: telegram, discord, slack, kook, lark, ...),
|
|
56
|
+
# such as telegram:-1001234567 or discord:4242. A bare id, or qq:<id>, is a
|
|
57
|
+
# QQ number. None of these is needed for `personagent chat`.
|
|
58
|
+
|
|
59
|
+
# The admin: the one person who runs the bot, with an account on as many
|
|
60
|
+
# platforms as you list. The bot is closest to them, they may manage what it
|
|
61
|
+
# remembers about a group, and they may teach it on their own.
|
|
62
|
+
ADMIN_IDS=
|
|
63
|
+
ADMIN_NAME=
|
|
64
|
+
# How the bot relates to the admin, such as brother, boss or friend.
|
|
65
|
+
# Blank = not mentioned in prompts.
|
|
66
|
+
ADMIN_RELATIONSHIP=
|
|
67
|
+
|
|
68
|
+
# The groups the bot answers, and who besides the admin may DM it. Each
|
|
69
|
+
# platform is gated on its own. A platform with no entries here is not
|
|
70
|
+
# restricted by the agent: every QQ group is answered, a QQ DM needs the admin
|
|
71
|
+
# or an entry, and any other platform is left to the connector's allowlist
|
|
72
|
+
# (such as the AstrBot plugin's groups and dm_users). One entry for a platform
|
|
73
|
+
# restricts that platform to its entries. DM users get the "ordinary friend"
|
|
74
|
+
# persona: looser than in a group, but not the admin's.
|
|
75
|
+
ACCESS_GROUPS=
|
|
76
|
+
ACCESS_DM_USERS=
|
|
77
|
+
|
|
78
|
+
# ============================================================================
|
|
79
|
+
# CONNECTORS (the AstrBot plugin, Satori, Matrix)
|
|
80
|
+
# ============================================================================
|
|
81
|
+
|
|
82
|
+
# POST /v1/events takes messages forwarded from chat platforms and returns the
|
|
83
|
+
# replies in its response (docs/connectors.md).
|
|
84
|
+
# CONNECTOR_TOKEN is the secret the connector signs each request with: a bearer
|
|
85
|
+
# header plus HMAC-SHA256(timestamp + "." + nonce + "." + exact JSON body),
|
|
86
|
+
# checked against replays. Blank is accepted only on loopback; forwarding from
|
|
87
|
+
# another host needs HTTPS (or a private tunnel ending on loopback) and a token.
|
|
88
|
+
# `personagent connect astrbot` writes the same token on both sides.
|
|
89
|
+
CONNECTOR_TOKEN=
|
|
90
|
+
# Events whose sent_at is older than this many seconds are refused even inside
|
|
91
|
+
# a fresh request, which allows an adapter's delayed delivery for up to 24 h.
|
|
92
|
+
CONNECTOR_MAX_EVENT_AGE_S=86400
|
|
93
|
+
# Connector platforms whose ids arrive bare instead of "<platform>:<id>".
|
|
94
|
+
# Set it to the connector's QQ adapter (AstrBot calls it aiocqhttp) to run QQ
|
|
95
|
+
# through a connector: QQ ids then stay plain numbers, the way NapCat and every
|
|
96
|
+
# store on disk spell them. Leave it blank otherwise.
|
|
97
|
+
# Naming a platform here lets its connector address QQ conversations, because
|
|
98
|
+
# bare ids are what the QQ entries of ADMIN_IDS, ACCESS_GROUPS and
|
|
99
|
+
# ACCESS_DM_USERS are compared against. Only QQ's adapter belongs here.
|
|
100
|
+
CONNECTOR_QQ_PLATFORMS=
|
|
101
|
+
# Messages nobody asked for (openers, the follow-up question after a rejection,
|
|
102
|
+
# the excuse when the model call fails) reach a forwarded platform only through
|
|
103
|
+
# a connector that polls POST /v1/outbox and says so ("capabilities":
|
|
104
|
+
# ["outbox"], see docs/connectors.md). false turns the outbox off: the endpoint
|
|
105
|
+
# answers 404, and such messages go out on QQ through NapCat only.
|
|
106
|
+
CONNECTOR_OUTBOX_ENABLED=true
|
|
107
|
+
# Connector turns run at the same time. /v1/events holds a slot for a whole
|
|
108
|
+
# turn, so it has its own budget. Blank = QQ_ONEBOT_MAX_INFLIGHT.
|
|
109
|
+
CONNECTOR_MAX_INFLIGHT=
|
|
110
|
+
|
|
111
|
+
# ============================================================================
|
|
112
|
+
# SERVICE AND STORAGE
|
|
113
|
+
# ============================================================================
|
|
114
|
+
|
|
115
|
+
# Where personagent listens. Loopback by default (blank too), so nothing is
|
|
116
|
+
# exposed. A split deployment may set SERVER_HOST=0.0.0.0, but then startup
|
|
117
|
+
# requires CONNECTOR_TOKEN, and /v1/onebot is off unless QQ_ONEBOT_SECRET is set.
|
|
118
|
+
SERVER_HOST=127.0.0.1
|
|
119
|
+
SERVER_PORT=8080
|
|
120
|
+
# The web page at http://127.0.0.1:<SERVER_PORT>/: status, why it spoke or
|
|
121
|
+
# stayed quiet, and what it learned, with promote / reject / roll back. It
|
|
122
|
+
# opens only through its private link (the token in runtime/dashboard.token),
|
|
123
|
+
# which `personagent run` and `personagent doctor` print. false leaves it out.
|
|
124
|
+
DASHBOARD_ENABLED=true
|
|
125
|
+
# The largest request body either endpoint accepts, in bytes.
|
|
126
|
+
SERVER_MAX_BODY_BYTES=8000000
|
|
127
|
+
# Logs go to the console. A path here also writes rotating log files, which can
|
|
128
|
+
# contain conversation details; keep it outside the repository or gitignored.
|
|
129
|
+
SERVER_LOG_FILE=
|
|
130
|
+
|
|
131
|
+
# The deployment folder: .env, persona.txt, runtime/ and the instance lock are
|
|
132
|
+
# resolved under it. Blank = this checkout, or the folder `personagent init`
|
|
133
|
+
# set up (~/personagent by default). AGENT_RUNTIME_DIR must stay beneath it.
|
|
134
|
+
# Set it to run several personas from one installed copy.
|
|
135
|
+
AGENT_HOME=
|
|
136
|
+
|
|
137
|
+
# Everything the bot learns or remembers (memory, evaluations, ledgers,
|
|
138
|
+
# learned pools, sticker notes) is written here, never into data/. Relative
|
|
139
|
+
# paths are under AGENT_HOME. runtime/ is gitignored; another folder inside a
|
|
140
|
+
# repository needs the same, because it holds real conversations.
|
|
141
|
+
AGENT_RUNTIME_DIR=runtime
|
|
142
|
+
|
|
143
|
+
# false keeps the service up but the agent answers nothing.
|
|
144
|
+
AGENT_ENABLED=true
|
|
145
|
+
|
|
146
|
+
# ============================================================================
|
|
147
|
+
# OPTIONAL FEATURES (safe to leave as they are)
|
|
148
|
+
# ============================================================================
|
|
149
|
+
|
|
150
|
+
# --- Model calls ---
|
|
151
|
+
# Per-request timeout in seconds, and retries after a transient error.
|
|
152
|
+
LLM_TIMEOUT_S=120
|
|
153
|
+
LLM_MAX_RETRIES=2
|
|
154
|
+
# Another model name for DMs, served by the same endpoint and key as LLM_MODEL.
|
|
155
|
+
# The exception: a name equal to LLM_FALLBACK_MODEL is served where the
|
|
156
|
+
# fallback is. Blank = LLM_MODEL.
|
|
157
|
+
LLM_DM_MODEL=
|
|
158
|
+
# The cheap first step when the bot speaks on its own (judging whether to join
|
|
159
|
+
# in, follow-ups, openers) asks this model only "reply or stay quiet?". The
|
|
160
|
+
# line that is sent is written by the main model. Blank = LLM_FALLBACK_MODEL,
|
|
161
|
+
# else the main model. Point it at the cheapest model you have.
|
|
162
|
+
LLM_JUDGE_MODEL=
|
|
163
|
+
|
|
164
|
+
# --- Fallback when busy (a cheaper model while the main one is loaded) ---
|
|
165
|
+
LLM_FALLBACK_MODEL=
|
|
166
|
+
# The fallback model's own endpoint, so an outage at the main provider is not
|
|
167
|
+
# also the fallback's. Blank = LLM_BASE_URL and LLM_API_KEY. Only a
|
|
168
|
+
# LLM_FALLBACK_MODEL different from LLM_MODEL is sent here, together with the
|
|
169
|
+
# judge, self-eval and reaction calls whose models default to it. A blank key
|
|
170
|
+
# with a URL on another provider sends LLM_API_KEY there, so give it its own.
|
|
171
|
+
# Accepts the same spellings as LLM_BASE_URL.
|
|
172
|
+
LLM_FALLBACK_BASE_URL=
|
|
173
|
+
LLM_FALLBACK_API_KEY=
|
|
174
|
+
# DeepSeek's `thinking` field turns hidden reasoning off for the judge, the
|
|
175
|
+
# search decision and the sticker tagger. DeepSeek, Zhipu, Moonshot and
|
|
176
|
+
# Volcengine hosts get it; OpenAI, Groq, Gemini, OpenRouter, Mistral and
|
|
177
|
+
# Anthropic do not; any other endpoint is asked on its first such call, and
|
|
178
|
+
# the answer is kept per model. true = send it to the fallback's host without
|
|
179
|
+
# asking. An endpoint that answers 400 to it is not sent it again.
|
|
180
|
+
LLM_FALLBACK_THINKING=false
|
|
181
|
+
# When LLM_RATE_THRESHOLD calls fall within LLM_RATE_WINDOW_S seconds, the
|
|
182
|
+
# next LLM_FALLBACK_DURATION_S seconds use the fallback model.
|
|
183
|
+
LLM_RATE_WINDOW_S=120
|
|
184
|
+
LLM_RATE_THRESHOLD=30
|
|
185
|
+
LLM_FALLBACK_DURATION_S=180
|
|
186
|
+
# Seconds a model that answered 429 (rate limited) is skipped. Shorter than
|
|
187
|
+
# LLM_FALLBACK_DURATION_S because a throttled model is metered, not broken.
|
|
188
|
+
# Any other failure (a 400, retries used up) keeps the model out for
|
|
189
|
+
# LLM_FALLBACK_DURATION_S.
|
|
190
|
+
LLM_RATE_LIMIT_COOLDOWN_S=20
|
|
191
|
+
|
|
192
|
+
# --- Conversation ---
|
|
193
|
+
# Messages from others before the bot considers joining in unasked.
|
|
194
|
+
CHAT_TRIGGER_COUNT=30
|
|
195
|
+
# Messages of history kept per conversation for the prompt.
|
|
196
|
+
CHAT_CONTEXT_MESSAGES=120
|
|
197
|
+
# Seconds after the bot's reply during which new messages count as follow-ups.
|
|
198
|
+
CHAT_FOLLOWUP_WINDOW_S=120
|
|
199
|
+
# The notes file under AGENT_RUNTIME_DIR, and how many notes each
|
|
200
|
+
# conversation keeps.
|
|
201
|
+
MEMORY_FILE=memory.json
|
|
202
|
+
MEMORY_MAX_PER_CONVERSATION=50
|
|
203
|
+
|
|
204
|
+
# --- Web search (looks up unfamiliar things) ---
|
|
205
|
+
# With a Tavily key it uses Tavily (more reliable); blank uses DuckDuckGo,
|
|
206
|
+
# which needs no key (the `ddgs` package from requirements.txt).
|
|
207
|
+
TAVILY_API_KEY=
|
|
208
|
+
|
|
209
|
+
# --- Vision (images and stickers) ---
|
|
210
|
+
# Blank = no vision model, only OCR, which costs nothing. Any OpenAI-compatible
|
|
211
|
+
# vision model works; give it its provider's key and base URL here, since there
|
|
212
|
+
# is no default endpoint.
|
|
213
|
+
VISION_MODEL=
|
|
214
|
+
VISION_API_KEY=
|
|
215
|
+
VISION_BASE_URL=
|
|
216
|
+
# The largest decoded image accepted from base64, a file or HTTP, in bytes.
|
|
217
|
+
VISION_MAX_IMAGE_BYTES=5000000
|
|
218
|
+
|
|
219
|
+
# --- Self-eval (scores each reply 1-5 into eval.jsonl, in the background) ---
|
|
220
|
+
# Off by default, so a first run costs least. Prefer a model from another
|
|
221
|
+
# vendor than the chat model: a model family is blind to its own failure
|
|
222
|
+
# modes. An EVAL_MODEL containing "moonshot" or "kimi" goes to the vision
|
|
223
|
+
# endpoint above.
|
|
224
|
+
EVAL_ENABLED=false
|
|
225
|
+
EVAL_MODEL=
|
|
226
|
+
EVAL_FILE=eval.jsonl
|
|
227
|
+
|
|
228
|
+
# --- Proactive messages (the bot sometimes speaks first) ---
|
|
229
|
+
# Off by default. When on, a background loop may start a conversation after a
|
|
230
|
+
# chat has been quiet for a while (outside the sleep window), with cooldowns
|
|
231
|
+
# and a low chance, and the model is told to stay quiet unless it has
|
|
232
|
+
# something to say. Groups and DMs, but only people and groups the bot has
|
|
233
|
+
# seen talk since it started. On QQ it sends through NapCat, and DMs go only to
|
|
234
|
+
# the QQ ids in ADMIN_IDS and ACCESS_DM_USERS. Elsewhere it needs a connector
|
|
235
|
+
# that pulls the outbox (CONNECTOR_OUTBOX_ENABLED), and DMs go to anyone that
|
|
236
|
+
# connector lets through.
|
|
237
|
+
PROACTIVE_ENABLED=false
|
|
238
|
+
# Platforms it may speak first on, comma-separated (qq, telegram, discord,
|
|
239
|
+
# ...); blank = every platform it can reach.
|
|
240
|
+
PROACTIVE_PLATFORMS=
|
|
241
|
+
# How often the loop checks, in seconds (25 min).
|
|
242
|
+
PROACTIVE_INTERVAL_S=1500
|
|
243
|
+
# A group must be quiet this long first, in seconds (45 min).
|
|
244
|
+
PROACTIVE_MIN_SILENCE_S=2700
|
|
245
|
+
# Least time between openers in one group, in seconds (3 h).
|
|
246
|
+
PROACTIVE_COOLDOWN_S=10800
|
|
247
|
+
# Chance per eligible check, 0 to 1.
|
|
248
|
+
PROACTIVE_PROB=0.25
|
|
249
|
+
# A DM must be quiet this long first, in seconds (4 h).
|
|
250
|
+
PROACTIVE_DM_MIN_SILENCE_S=14400
|
|
251
|
+
# Least time between DMs to one person, in seconds (24 h).
|
|
252
|
+
PROACTIVE_DM_COOLDOWN_S=86400
|
|
253
|
+
# Chance per eligible check for a DM, 0 to 1.
|
|
254
|
+
PROACTIVE_DM_PROB=0.2
|
|
255
|
+
|
|
256
|
+
# --- Learning from reactions ---
|
|
257
|
+
# On by default. Each reply waits a while for a reaction aimed at it: a quote
|
|
258
|
+
# of the bot's message, a mention or its name, or in a DM the other person's
|
|
259
|
+
# next message. One cheap model call reads the reaction as a correction,
|
|
260
|
+
# rejection, positive or neutral, and filters out banter and trolling.
|
|
261
|
+
# A reaction is recorded as evidence (append-only, in
|
|
262
|
+
# runtime/evidence.<lang>.jsonl) and may propose a candidate. A candidate
|
|
263
|
+
# changes nothing until it is promoted (next block). Every reading is also
|
|
264
|
+
# logged in candidates.jsonl (src=user_reaction).
|
|
265
|
+
REACT_LEARN_ENABLED=true
|
|
266
|
+
# How long a reply waits for a reaction, in seconds (15 min).
|
|
267
|
+
REACT_TTL_S=900
|
|
268
|
+
# Replies tracked per conversation.
|
|
269
|
+
REACT_MAX_PENDING=4
|
|
270
|
+
# The model that reads reactions. Blank = LLM_JUDGE_MODEL (the cheapest
|
|
271
|
+
# configured).
|
|
272
|
+
REACT_MODEL=
|
|
273
|
+
# After a rejection, how long the bot's next reply still counts as its second
|
|
274
|
+
# try, in seconds.
|
|
275
|
+
REACT_FIX_WINDOW_S=600
|
|
276
|
+
# After an accepted rejection, the bot may later ask what the person meant
|
|
277
|
+
# (delayed, with a cooldown).
|
|
278
|
+
REACT_ELICIT_ENABLED=true
|
|
279
|
+
# Seconds to wait before asking, so it never talks over its own reply to the
|
|
280
|
+
# rejection.
|
|
281
|
+
REACT_ELICIT_DELAY_S=120
|
|
282
|
+
# Least time between such questions in one conversation, in seconds.
|
|
283
|
+
REACT_ELICIT_COOLDOWN_S=3600
|
|
284
|
+
|
|
285
|
+
# --- Promotion (when learned material may change replies) ---
|
|
286
|
+
# A reaction is evidence, and reading it creates a candidate. Promotion gives a
|
|
287
|
+
# candidate a say in future replies; a rollback or a newer candidate takes it
|
|
288
|
+
# away. Only promoted candidates are used, through
|
|
289
|
+
# runtime/promoted.{examples,feedback}.<lang>.jsonl, a view rebuilt from the
|
|
290
|
+
# append-only ledger and never edited by hand.
|
|
291
|
+
# The defaults make one thing impossible: a single automatic signal changing
|
|
292
|
+
# for good how the bot talks. Loosen them only while watching the results.
|
|
293
|
+
# Review what is waiting with `personagent learned list`.
|
|
294
|
+
#
|
|
295
|
+
# Strong = an explicit correction with a concrete better line, from the person
|
|
296
|
+
# the reply was meant for, or a second try that person accepted.
|
|
297
|
+
# Weaker = a rejection with nothing concrete, a correction from a bystander,
|
|
298
|
+
# or the bot's own review. Real evidence, not a mandate.
|
|
299
|
+
# Weak = laughter, agreement, banter, the bot's own score. Never promotes
|
|
300
|
+
# anything on its own, so good examples are promoted by you.
|
|
301
|
+
# Being the admin does not stand in for being the person the reply was for,
|
|
302
|
+
# and conflicting evidence blocks automatic promotion.
|
|
303
|
+
#
|
|
304
|
+
# false = nothing is promoted without you.
|
|
305
|
+
PROMOTE_AUTO_ENABLED=true
|
|
306
|
+
# Distinct agreeing events needed (at least 2).
|
|
307
|
+
PROMOTE_MIN_EVENTS=2
|
|
308
|
+
# Of which this many must be strong (at least 1).
|
|
309
|
+
PROMOTE_MIN_STRONG=1
|
|
310
|
+
# From this many different people (at least 1). One person can supply both
|
|
311
|
+
# events, by correcting a reply and then accepting the retry; an honest
|
|
312
|
+
# clarification looks exactly like misuse of it. 2 stops a stranger from
|
|
313
|
+
# teaching the bot alone in a room: the admin is exempt, and a candidate held
|
|
314
|
+
# back this way still waits for you to approve.
|
|
315
|
+
PROMOTE_MIN_SPEAKERS=1
|
|
316
|
+
# Evidence older than this many days stops counting; 0 = no limit.
|
|
317
|
+
PROMOTE_EVIDENCE_MAX_AGE_DAYS=30
|
|
318
|
+
# Never combine evidence from different conversations.
|
|
319
|
+
PROMOTE_REQUIRE_SAME_CONVERSATION=true
|
|
320
|
+
|
|
321
|
+
# --- Size of the learned pools ---
|
|
322
|
+
# Each reply picks 4 examples and 6 better-reply pairs from the read-only data/
|
|
323
|
+
# seeds, the learned runtime/ pools and the promoted views. These caps bound
|
|
324
|
+
# the machine-written part: they size the promoted views, and the offline
|
|
325
|
+
# tools apply them to what they write. Older material came from an older
|
|
326
|
+
# prompt, and without a cap it outvotes the recent. Raise them for very varied
|
|
327
|
+
# topics; 0 = no cap. What you wrote or approved yourself is never counted or
|
|
328
|
+
# dropped.
|
|
329
|
+
PROMOTE_MAX_EXAMPLES=500
|
|
330
|
+
PROMOTE_MAX_FEEDBACK=500
|
|
331
|
+
|
|
332
|
+
# --- Self-improvement loop (from self-eval scores to candidates) ---
|
|
333
|
+
# Off by default. When on, a background loop takes new low scores from
|
|
334
|
+
# eval.jsonl, has a model diagnose each and draft a better reply, and files it
|
|
335
|
+
# as a candidate. Nothing is applied: a self-diagnosis is one signal nobody
|
|
336
|
+
# witnessed, so it waits for a real reaction to agree, or for you to promote it.
|
|
337
|
+
# The same with a review step: python tools/auto_reviewer.py --apply
|
|
338
|
+
# Needs EVAL_ENABLED=true.
|
|
339
|
+
EVOLVE_AUTO_ENABLED=false
|
|
340
|
+
# Hours between looks at new scores.
|
|
341
|
+
EVOLVE_INTERVAL_HOURS=6
|
|
342
|
+
# A score at or below this counts as a miss (3 = drifting into an assistant's
|
|
343
|
+
# voice, the band this loop is for).
|
|
344
|
+
EVOLVE_THRESHOLD=3
|
|
345
|
+
# Most entries diagnosed per round.
|
|
346
|
+
EVOLVE_BATCH=5
|
|
347
|
+
# Blank = EVAL_MODEL, else the chat model.
|
|
348
|
+
EVOLVE_MODEL=
|
|
349
|
+
|
|
350
|
+
# --- Retrieval by meaning (embeddings) ---
|
|
351
|
+
# Retrieval ranks examples, pairs and notes on the words they share with the
|
|
352
|
+
# message (BM25), where they were learned (this conversation, then this
|
|
353
|
+
# persona, then the shipped seeds) and how recent they are. An embedding model
|
|
354
|
+
# adds meaning: a row that says the same thing in other words can win.
|
|
355
|
+
# Blank EMBEDDING_MODEL = off. Any OpenAI-compatible /embeddings endpoint
|
|
356
|
+
# works (OpenAI, SiliconFlow, Zhipu, a local Ollama). Vectors are cached in
|
|
357
|
+
# AGENT_RUNTIME_DIR/embeddings.jsonl. A reply waits at most 3 seconds for its
|
|
358
|
+
# message to be embedded; a slow or failing endpoint is logged once, and
|
|
359
|
+
# retrieval ranks without it until it answers.
|
|
360
|
+
EMBEDDING_MODEL=
|
|
361
|
+
# Blank = LLM_BASE_URL with LLM_API_KEY. A URL of its own gets only
|
|
362
|
+
# EMBEDDING_API_KEY (blank for an endpoint that needs no key). Accepts a root,
|
|
363
|
+
# a version base (/v1, /api/paas/v4) or the full /embeddings URL.
|
|
364
|
+
EMBEDDING_BASE_URL=
|
|
365
|
+
EMBEDDING_API_KEY=
|
|
366
|
+
|
|
367
|
+
# --- Offline tools (not read by the running bot) ---
|
|
368
|
+
# Listed so the startup check knows these names are real settings.
|
|
369
|
+
# tools/prompt_lab.py writes through a different vendor than the agent under
|
|
370
|
+
# test, which makes it a measurement rather than a mirror. Needs
|
|
371
|
+
# `pip install -e ".[judge]"`.
|
|
372
|
+
ANTHROPIC_API_KEY=
|
|
373
|
+
ANTHROPIC_BASE_URL=
|
|
374
|
+
# Required by the lab: a model the vendor above serves.
|
|
375
|
+
LAB_MODEL=
|
|
376
|
+
# tools/auto_reviewer.py; blank = EVAL_MODEL, else the chat model.
|
|
377
|
+
REVIEWER_MODEL=
|
|
378
|
+
# The scoring model of `personagent eval` (persona and learning suites) and
|
|
379
|
+
# tools/evolution_benchmark.py --judge, again from another vendor than the one
|
|
380
|
+
# measured. BENCH_JUDGE_BASE_URL and BENCH_JUDGE_API_KEY default to
|
|
381
|
+
# LLM_BASE_URL and LLM_API_KEY.
|
|
382
|
+
BENCH_JUDGE_MODEL=
|
|
383
|
+
BENCH_JUDGE_API_KEY=
|
|
384
|
+
BENCH_JUDGE_BASE_URL=
|
|
385
|
+
BENCH_EVAL_DELAY_S=
|
|
386
|
+
|
|
387
|
+
# --- Ledger size warnings ---
|
|
388
|
+
# The evidence log and the candidate ledger are append-only and never shrink.
|
|
389
|
+
# These are the sizes, in bytes, at which each starts warning in the log; they
|
|
390
|
+
# do not cap or rotate anything.
|
|
391
|
+
LEDGER_EVIDENCE_WARN_BYTES=
|
|
392
|
+
LEDGER_CANDIDATES_WARN_BYTES=
|
|
393
|
+
|
|
394
|
+
# ============================================================================
|
|
395
|
+
# QQ THROUGH NAPCAT (OneBot v11)
|
|
396
|
+
# ============================================================================
|
|
397
|
+
|
|
398
|
+
# QQ comes in through AstrBot (CONNECTOR_QQ_PLATFORMS above). The direct
|
|
399
|
+
# OneBot route, NapCat posting to /v1/onebot, is deprecated and still served.
|
|
400
|
+
# Which QQ groups the bot answers is ACCESS_GROUPS.
|
|
401
|
+
|
|
402
|
+
# The bot account's QQ number, on either route.
|
|
403
|
+
QQ_BOT_ID=
|
|
404
|
+
|
|
405
|
+
# NapCat's HTTP server, such as http://127.0.0.1:3000. On the direct route
|
|
406
|
+
# every reply goes out through it; through AstrBot it is only used for
|
|
407
|
+
# proactive sends and the sweep for mentions missed while the bot was busy.
|
|
408
|
+
# Blank = not used. Events never come this way; they reach SERVER_PORT.
|
|
409
|
+
QQ_ONEBOT_URL=
|
|
410
|
+
|
|
411
|
+
# If NapCat hands over received images as file:// paths (its local-cache
|
|
412
|
+
# mode), set this to that cache folder. Blank refuses every file:// path.
|
|
413
|
+
QQ_ONEBOT_IMAGE_DIR=
|
|
414
|
+
|
|
415
|
+
# The `secret` in NapCat's HTTP client config. Read only by the direct route:
|
|
416
|
+
# with it set, each /v1/onebot body must carry a matching
|
|
417
|
+
# `x-signature: sha1=<hex>` header. Blank accepts only programs on this
|
|
418
|
+
# machine, and nothing at all when SERVER_HOST is not loopback.
|
|
419
|
+
QQ_ONEBOT_SECRET=
|
|
420
|
+
|
|
421
|
+
# Expensive OneBot requests handled at the same time. Requests beyond this get
|
|
422
|
+
# HTTP 429 instead of piling up memory and model calls.
|
|
423
|
+
QQ_ONEBOT_MAX_INFLIGHT=64
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Qiankang (Kant) Wang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# What setup.py bundles into the wheel, so a wheel built from the sdist has it too.
|
|
2
|
+
include requirements.txt .env.example
|
|
3
|
+
graft data
|
|
4
|
+
graft integrations/astrbot/astrbot_plugin_personagent
|
|
5
|
+
# The sdist builds the package; the test suite runs from a checkout.
|
|
6
|
+
prune tests
|
|
7
|
+
global-exclude *.py[cod]
|