@thesashadev/girl-agent 0.1.17 → 0.1.18

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.18
4
+
5
+ Дата: 2026-05-09
6
+
7
+ - chore(ci): switch changelog model to gpt-5-mini
8
+ - feat(ci): AI-powered changelog generation via GitHub Models API
9
+ - Improve profile and model config UX
10
+
11
+
3
12
  ## 0.1.17
4
13
 
5
14
  Дата: 2026-05-09
package/dist/cli.js CHANGED
@@ -946,6 +946,12 @@ async function writeConfig(cfg) {
946
946
  "utf8"
947
947
  );
948
948
  }
949
+ async function deleteProfile(slug) {
950
+ if (!slug || slug.includes("/") || slug.includes("\\") || slug === "." || slug === "..") {
951
+ throw new Error(`\u043D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 slug \u043F\u0440\u043E\u0444\u0438\u043B\u044F: ${slug}`);
952
+ }
953
+ await fs.rm(profileDir(slug), { recursive: true, force: true });
954
+ }
949
955
  function normalizeOwnerId(value) {
950
956
  if (typeof value === "number" && Number.isSafeInteger(value) && value > 0) return value;
951
957
  if (typeof value === "string" && /^\d+$/.test(value.trim())) {
@@ -1330,6 +1336,8 @@ var OpenAILike = class {
1330
1336
  } catch (err) {
1331
1337
  process.stderr.write(`[oauth] token refresh failed: ${err instanceof Error ? err.message : err}
1332
1338
  `);
1339
+ this.cfg.oauthRefreshToken = void 0;
1340
+ this.cfg.oauthExpiresAt = void 0;
1333
1341
  }
1334
1342
  }
1335
1343
  async chat(messages, opts = {}) {
@@ -2980,6 +2988,9 @@ function Dashboard({ runtime }) {
2980
2988
  case "status":
2981
2989
  append(await runtime.cmdStatus());
2982
2990
  break;
2991
+ case "model":
2992
+ append(await runtime.cmdModel(rest));
2993
+ break;
2983
2994
  case "reset":
2984
2995
  append(await runtime.cmdReset());
2985
2996
  setScore({ interest: 0, trust: 0, attraction: 0, annoyance: 0, cringe: 0 });
@@ -3035,7 +3046,7 @@ function Dashboard({ runtime }) {
3035
3046
  break;
3036
3047
  }
3037
3048
  case "help":
3038
- append(":status :why :amnesia <\u043C\u0438\u043D> [chatId] :reset :stage <id|num> :wake [chatId] :debug [chatId] :pause :resume :cringe :relationship :persona :log [YYYY-MM-DD] [chars] :sticker [chatId] :quit");
3049
+ append(":status :model [provider] [model=...] [api-key=...] :why :amnesia <\u043C\u0438\u043D> [chatId] :reset :stage <id|num> :wake [chatId] :debug [chatId] :pause :resume :cringe :relationship :persona :log [YYYY-MM-DD] [chars] :sticker [chatId] :quit");
3039
3050
  break;
3040
3051
  case "quit":
3041
3052
  case "exit":
@@ -5098,6 +5109,57 @@ async function addStickerToLibrary(cfg, fileId, emoji = "", tags = []) {
5098
5109
 
5099
5110
  // src/engine/runtime.ts
5100
5111
  import { EventEmitter } from "events";
5112
+
5113
+ // src/config/llm-update.ts
5114
+ init_esm_shims();
5115
+ function describeLLM(cfg) {
5116
+ const preset = findPreset(cfg.llm.presetId);
5117
+ const auth = cfg.llm.oauthRefreshToken ? "oauth" : cfg.llm.apiKey.trim() ? "api-key" : "\u0431\u0435\u0437 \u043A\u043B\u044E\u0447\u0430";
5118
+ return [
5119
+ `provider: ${preset?.name ?? cfg.llm.presetId}`,
5120
+ `preset: ${cfg.llm.presetId}`,
5121
+ `proto: ${cfg.llm.proto}`,
5122
+ `model: ${cfg.llm.model || "\u2014"}`,
5123
+ `baseURL: ${cfg.llm.baseURL ?? "default"}`,
5124
+ `auth: ${auth}`
5125
+ ].join("\n");
5126
+ }
5127
+ function applyLLMUpdate(cfg, update) {
5128
+ const changed = [];
5129
+ const currentPresetId = cfg.llm.presetId;
5130
+ const presetId = update.presetId ?? currentPresetId;
5131
+ const preset = findPreset(presetId);
5132
+ const presetChanged = presetId !== currentPresetId;
5133
+ const proto = update.proto ?? preset?.proto ?? cfg.llm.proto;
5134
+ const baseURL = update.baseURL !== void 0 ? emptyToUndefined(update.baseURL) : presetChanged ? preset?.baseURL : cfg.llm.baseURL;
5135
+ const model = update.model ?? (presetChanged ? preset?.defaultModel : cfg.llm.model) ?? "";
5136
+ const apiKey = update.apiKey !== void 0 ? update.apiKey : presetChanged ? preset?.defaultApiKey ?? "" : cfg.llm.apiKey;
5137
+ const keepOAuth = !presetChanged && update.apiKey === void 0 && preset?.oauth;
5138
+ if (presetChanged) changed.push(`provider ${currentPresetId} \u2192 ${presetId}`);
5139
+ if (cfg.llm.model !== model) changed.push(`model ${cfg.llm.model || "\u2014"} \u2192 ${model || "\u2014"}`);
5140
+ if (cfg.llm.proto !== proto) changed.push(`proto ${cfg.llm.proto} \u2192 ${proto}`);
5141
+ if ((cfg.llm.baseURL ?? "") !== (baseURL ?? "")) changed.push("baseURL \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D");
5142
+ if (update.apiKey !== void 0) changed.push("apiKey \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D");
5143
+ if (!keepOAuth && cfg.llm.oauthRefreshToken) changed.push("\u0441\u0442\u0430\u0440\u044B\u0439 OAuth \u043E\u0447\u0438\u0449\u0435\u043D");
5144
+ cfg.llm = {
5145
+ presetId,
5146
+ proto,
5147
+ baseURL,
5148
+ apiKey,
5149
+ model,
5150
+ ...keepOAuth ? {
5151
+ oauthRefreshToken: cfg.llm.oauthRefreshToken,
5152
+ oauthExpiresAt: cfg.llm.oauthExpiresAt
5153
+ } : {}
5154
+ };
5155
+ return changed;
5156
+ }
5157
+ function emptyToUndefined(value) {
5158
+ const trimmed = value.trim();
5159
+ return trimmed ? trimmed : void 0;
5160
+ }
5161
+
5162
+ // src/engine/runtime.ts
5101
5163
  var Runtime = class extends EventEmitter {
5102
5164
  constructor(cfg) {
5103
5165
  super();
@@ -5857,13 +5919,45 @@ ${herLastMessages.map((m) => `- "${m}"`).join("\n")}
5857
5919
  `\u0441\u0442\u0430\u0434\u0438\u044F: ${stage.label} (${this.cfg.stage})`,
5858
5920
  `primary owner: ${this.cfg.ownerId ?? "\u2014"}`,
5859
5921
  `privacy: ${this.cfg.privacy ?? "owner-only"}`,
5922
+ `llm: ${this.cfg.llm.presetId}/${this.cfg.llm.model || "\u2014"} (${this.cfg.llm.proto})`,
5860
5923
  `presence: ${this.presenceProfile.pattern}`,
5861
5924
  `communication: ${communicationProfileLabel(communication)}`,
5925
+ `config: ${profileDir(this.cfg.slug)}/config.json`,
5862
5926
  `score: ${JSON.stringify(rel.score)}`,
5863
5927
  `mcp: ${this.mcps.map((m) => m.id).join(", ") || "\u2014"}`,
5864
5928
  `paused: ${this.paused}`
5865
5929
  ].join("\n");
5866
5930
  }
5931
+ async cmdModel(args) {
5932
+ const parts = args.map((x) => x.trim()).filter(Boolean);
5933
+ if (!parts.length || parts[0] === "show") return describeLLM(this.cfg);
5934
+ const update = {};
5935
+ for (const part of parts) {
5936
+ const eq = part.indexOf("=");
5937
+ if (eq === -1) {
5938
+ if (!update.presetId && findPreset(part)) update.presetId = part;
5939
+ else update.model = part;
5940
+ continue;
5941
+ }
5942
+ const key = part.slice(0, eq);
5943
+ const value = part.slice(eq + 1);
5944
+ if (key === "preset" || key === "provider" || key === "api-preset") update.presetId = value;
5945
+ else if (key === "model") update.model = value;
5946
+ else if (key === "key" || key === "api-key") update.apiKey = value;
5947
+ else if (key === "base-url" || key === "baseURL") update.baseURL = value;
5948
+ else if (key === "proto" && (value === "openai" || value === "anthropic")) update.proto = value;
5949
+ else throw new Error(`\u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 :model: ${key}`);
5950
+ }
5951
+ const changed = applyLLMUpdate(this.cfg, update);
5952
+ this.llm = makeLLM(this.cfg.llm);
5953
+ await writeConfig(this.cfg);
5954
+ return changed.length ? `\u043C\u043E\u0434\u0435\u043B\u044C \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0430 \u0431\u0435\u0437 \u0440\u0443\u0447\u043D\u043E\u0433\u043E config edit:
5955
+ ${changed.map((x) => `- ${x}`).join("\n")}
5956
+
5957
+ ${describeLLM(this.cfg)}` : `\u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C
5958
+
5959
+ ${describeLLM(this.cfg)}`;
5960
+ }
5867
5961
  async cmdReset() {
5868
5962
  if (this.cfg.stage === "dumped") this.cfg.stage = "tg-given-cold";
5869
5963
  await writeConfig(this.cfg);
@@ -6281,6 +6375,9 @@ async function runHeadlessJsonEvents(rt) {
6281
6375
  case "status":
6282
6376
  text = await rt.cmdStatus();
6283
6377
  break;
6378
+ case "model":
6379
+ text = await rt.cmdModel(rest);
6380
+ break;
6284
6381
  case "reset":
6285
6382
  text = await rt.cmdReset();
6286
6383
  break;
@@ -6347,7 +6444,7 @@ async function runHeadlessJsonEvents(rt) {
6347
6444
  return;
6348
6445
  }
6349
6446
  case "help":
6350
- text = ":status :why :amnesia :reset :stage :wake :debug :pause :resume :cringe :relationship :persona :log :sticker :snapshot :quit";
6447
+ text = ":status :model :why :amnesia :reset :stage :wake :debug :pause :resume :cringe :relationship :persona :log :sticker :snapshot :quit";
6351
6448
  break;
6352
6449
  case "quit":
6353
6450
  case "exit":
@@ -6596,6 +6693,8 @@ usage:
6596
6693
 
6597
6694
  girl-agent server --list
6598
6695
  girl-agent server --profile=<slug> --headless
6696
+ girl-agent server --profile=<slug> --set-model --api-preset=<id> --model=<model> [--api-key=<key>]
6697
+ girl-agent server --profile=<slug> --delete-profile --yes
6599
6698
 
6600
6699
  girl-agent server --print-systemd > /etc/systemd/system/girl-agent.service
6601
6700
  girl-agent server --print-docker
@@ -6621,6 +6720,9 @@ function parseServerArgs(argv) {
6621
6720
  jsonEvents: !!argv["json-events"],
6622
6721
  noStart: !!argv["no-start"] || argv.start === false,
6623
6722
  profile: typeof argv.profile === "string" ? argv.profile : void 0,
6723
+ setModel: !!argv["set-model"],
6724
+ deleteProfile: !!argv["delete-profile"],
6725
+ yes: !!argv.yes,
6624
6726
  list: !!argv.list,
6625
6727
  help: !!argv.help
6626
6728
  };
@@ -6650,6 +6752,46 @@ async function runServer(rawArgv) {
6650
6752
  `);
6651
6753
  return;
6652
6754
  }
6755
+ if (args.deleteProfile) {
6756
+ if (!args.profile) {
6757
+ process.stderr.write("--delete-profile \u0442\u0440\u0435\u0431\u0443\u0435\u0442 --profile=<slug>\n");
6758
+ process.exit(1);
6759
+ }
6760
+ if (!args.yes) {
6761
+ process.stderr.write(`\u043F\u0440\u043E\u0444\u0438\u043B\u044C \u041D\u0415 \u0443\u0434\u0430\u043B\u0451\u043D: \u0434\u043E\u0431\u0430\u0432\u044C --yes \u0434\u043B\u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F.
6762
+ \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043B\u0435\u043D\u043E: ${path6.join(DATA_ROOT, args.profile)}
6763
+ `);
6764
+ process.exit(1);
6765
+ }
6766
+ await deleteProfile(args.profile);
6767
+ process.stdout.write(`\u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0443\u0434\u0430\u043B\u0451\u043D: ${args.profile}
6768
+ data: ${DATA_ROOT}
6769
+ `);
6770
+ return;
6771
+ }
6772
+ if (args.setModel) {
6773
+ if (!args.profile) {
6774
+ process.stderr.write("--set-model \u0442\u0440\u0435\u0431\u0443\u0435\u0442 --profile=<slug>\n");
6775
+ process.exit(1);
6776
+ }
6777
+ const cfg = await readConfig(args.profile);
6778
+ if (!cfg) {
6779
+ process.stderr.write(`profile not found: ${args.profile}
6780
+ data dir: ${DATA_ROOT}
6781
+ `);
6782
+ process.exit(1);
6783
+ }
6784
+ const changed = applyLLMUpdate(cfg, {
6785
+ presetId: typeof rawArgv["api-preset"] === "string" ? rawArgv["api-preset"] : void 0,
6786
+ model: typeof rawArgv.model === "string" ? rawArgv.model : void 0,
6787
+ apiKey: typeof rawArgv["api-key"] === "string" ? rawArgv["api-key"] : void 0,
6788
+ baseURL: typeof rawArgv["base-url"] === "string" ? rawArgv["base-url"] : void 0,
6789
+ proto: rawArgv.proto === "anthropic" ? "anthropic" : rawArgv.proto === "openai" ? "openai" : void 0
6790
+ });
6791
+ await writeConfig(cfg);
6792
+ process.stdout.write((changed.length ? changed.map((x) => `- ${x}`).join("\n") : "\u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C") + "\n\n" + describeLLM(cfg) + "\n");
6793
+ return;
6794
+ }
6653
6795
  if (args.profile) {
6654
6796
  const cfg = await readConfig(args.profile);
6655
6797
  if (!cfg) {
@@ -7002,6 +7144,8 @@ usage:
7002
7144
  npx girl-agent # \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C TUI \u0432\u0438\u0437\u0430\u0440\u0434 (\u0438\u043B\u0438 \u0430\u0432\u0442\u043E\u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0435\u0441\u043B\u0438 1 \u043F\u0440\u043E\u0444\u0438\u043B\u044C)
7003
7145
  npx girl-agent --new # \u043F\u0440\u0438\u043D\u0443\u0434\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u043E\u0442\u043A\u0440\u044B\u0442\u044C \u0432\u0438\u0437\u0430\u0440\u0434 \u0434\u043B\u044F \u043D\u043E\u0432\u043E\u0433\u043E \u043F\u0440\u043E\u0444\u0438\u043B\u044F
7004
7146
  npx girl-agent --profile=<slug> # \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0433\u043E\u0442\u043E\u0432\u044B\u0439 \u043F\u0440\u043E\u0444\u0438\u043B\u044C
7147
+ npx girl-agent --profile=<slug> --set-model --api-preset=<id> --model=<model> [--api-key=<key>]
7148
+ npx girl-agent --profile=<slug> --delete-profile --yes
7005
7149
  npx girl-agent --reset --profile=<slug>
7006
7150
  npx girl-agent <flags> # \u043F\u0440\u043E\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0432\u0438\u0437\u0430\u0440\u0434 \u0441 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u0430\u043C\u0438
7007
7151
 
@@ -7039,7 +7183,10 @@ required flags \u0434\u043B\u044F headless setup (--name --age --stage --api-pre
7039
7183
  --stage=<id|num> 1=met-irl-got-tg 2=tg-given-cold 3=tg-given-warming 4=convinced 5=first-date-done 6=dating-early 7=dating-stable 8=long-term
7040
7184
  --mcp=exa:KEY \u043C\u043E\u0436\u043D\u043E \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0440\u0430\u0437
7041
7185
  --new \u043F\u0440\u0438\u043D\u0443\u0434\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u043E\u0442\u043A\u0440\u044B\u0442\u044C \u0432\u0438\u0437\u0430\u0440\u0434 \u0434\u043B\u044F \u043D\u043E\u0432\u043E\u0433\u043E \u043F\u0440\u043E\u0444\u0438\u043B\u044F
7042
- --list \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u0438
7186
+ --list \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u0438 \u0438 data dir
7187
+ --set-model \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C LLM \u0443 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0435\u0433\u043E \u043F\u0440\u043E\u0444\u0438\u043B\u044F \u0431\u0435\u0437 \u0440\u0443\u0447\u043D\u043E\u0433\u043E config edit
7188
+ --delete-profile \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0438\u0437 data dir
7189
+ --yes \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C \u043E\u043F\u0430\u0441\u043D\u043E\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0431\u0435\u0437 \u0432\u043E\u043F\u0440\u043E\u0441\u0430
7043
7190
  --help
7044
7191
 
7045
7192
  update:
@@ -7087,6 +7234,9 @@ async function main() {
7087
7234
  "json-events",
7088
7235
  "headless",
7089
7236
  "server",
7237
+ "set-model",
7238
+ "delete-profile",
7239
+ "yes",
7090
7240
  "print-config",
7091
7241
  "print-systemd",
7092
7242
  "print-docker",
@@ -7156,6 +7306,50 @@ async function main() {
7156
7306
  if (argv.list) {
7157
7307
  const list = await listProfiles();
7158
7308
  process.stdout.write(list.length ? list.join("\n") + "\n" : "(\u043D\u0435\u0442 \u043F\u0440\u043E\u0444\u0438\u043B\u0435\u0439)\n");
7309
+ process.stdout.write(`data: ${DATA_ROOT}
7310
+ `);
7311
+ return;
7312
+ }
7313
+ if (argv["delete-profile"]) {
7314
+ const slug = typeof argv.profile === "string" ? argv.profile : void 0;
7315
+ if (!slug) {
7316
+ process.stderr.write("--delete-profile \u0442\u0440\u0435\u0431\u0443\u0435\u0442 --profile=<slug>\n");
7317
+ process.exit(1);
7318
+ }
7319
+ if (!argv.yes) {
7320
+ process.stderr.write(`\u043F\u0440\u043E\u0444\u0438\u043B\u044C \u041D\u0415 \u0443\u0434\u0430\u043B\u0451\u043D: \u0434\u043E\u0431\u0430\u0432\u044C --yes \u0434\u043B\u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F.
7321
+ \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043B\u0435\u043D\u043E: ${DATA_ROOT}/${slug}
7322
+ `);
7323
+ process.exit(1);
7324
+ }
7325
+ await deleteProfile(slug);
7326
+ process.stdout.write(`\u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0443\u0434\u0430\u043B\u0451\u043D: ${slug}
7327
+ data: ${DATA_ROOT}
7328
+ `);
7329
+ return;
7330
+ }
7331
+ if (argv["set-model"]) {
7332
+ const slug = typeof argv.profile === "string" ? argv.profile : void 0;
7333
+ if (!slug) {
7334
+ process.stderr.write("--set-model \u0442\u0440\u0435\u0431\u0443\u0435\u0442 --profile=<slug>\n");
7335
+ process.exit(1);
7336
+ }
7337
+ const cfg = await readConfig(slug);
7338
+ if (!cfg) {
7339
+ process.stderr.write(`profile not found: ${slug}
7340
+ data dir: ${DATA_ROOT}
7341
+ `);
7342
+ process.exit(1);
7343
+ }
7344
+ const changed = applyLLMUpdate(cfg, {
7345
+ presetId: typeof argv["api-preset"] === "string" ? argv["api-preset"] : void 0,
7346
+ model: typeof argv.model === "string" ? argv.model : void 0,
7347
+ apiKey: typeof argv["api-key"] === "string" ? argv["api-key"] : void 0,
7348
+ baseURL: typeof argv["base-url"] === "string" ? argv["base-url"] : void 0,
7349
+ proto: argv.proto === "anthropic" ? "anthropic" : argv.proto === "openai" ? "openai" : void 0
7350
+ });
7351
+ await writeConfig(cfg);
7352
+ process.stdout.write((changed.length ? changed.map((x) => `- ${x}`).join("\n") : "\u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C") + "\n\n" + describeLLM(cfg) + "\n");
7159
7353
  return;
7160
7354
  }
7161
7355
  if (argv.profile && !argv.mode && !argv.name) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thesashadev/girl-agent",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "Telegram AI persona engine with memory, schedule, relationship state and MTProto userbot mode.",
5
5
  "type": "module",
6
6
  "bin": {