thinyai 0.1.8 → 0.1.9

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.
Files changed (2) hide show
  1. package/dist/bin.js +146 -15
  2. package/package.json +6 -6
package/dist/bin.js CHANGED
@@ -1829,11 +1829,14 @@ function applyConfig(cfg) {
1829
1829
  const set = (k, v) => {
1830
1830
  if (v && !process.env[k]) process.env[k] = v;
1831
1831
  };
1832
- set("THINY_MODEL", cfg.model);
1833
- if (cfg.apiKey) {
1834
- set(cfg.model?.startsWith("anthropic") ? "THINY_ANTHROPIC_API_KEY" : "THINY_OPENAI_API_KEY", cfg.apiKey);
1832
+ const prov = activeProvider(cfg);
1833
+ if (prov) {
1834
+ set("THINY_MODEL", prov.model);
1835
+ if (prov.apiKey) {
1836
+ set(prov.model.startsWith("anthropic") ? "THINY_ANTHROPIC_API_KEY" : "THINY_OPENAI_API_KEY", prov.apiKey);
1837
+ }
1838
+ set("THINY_OPENAI_BASE_URL", prov.baseUrl);
1835
1839
  }
1836
- set("THINY_OPENAI_BASE_URL", cfg.baseUrl);
1837
1840
  set("THINY_PERSONA_NAME", cfg.agentName);
1838
1841
  set("THINY_USER_ID", cfg.userId);
1839
1842
  if (cfg.sui?.network) {
@@ -1872,6 +1875,37 @@ function saveSuiWallet(cfg, network, wallet, makeActive) {
1872
1875
  if (makeActive || !cfg.sui.activeAddress) cfg.sui.activeAddress = wallet.address;
1873
1876
  saveConfig(cfg);
1874
1877
  }
1878
+ function providersOf(cfg) {
1879
+ if (!cfg) return [];
1880
+ if (cfg.providers && cfg.providers.length > 0) return cfg.providers;
1881
+ if (cfg.model) {
1882
+ const id = cfg.model.startsWith("anthropic") ? "anthropic" : cfg.baseUrl ? "custom" : "openai";
1883
+ return [{ id, label: cfg.model, model: cfg.model, apiKey: cfg.apiKey, baseUrl: cfg.baseUrl }];
1884
+ }
1885
+ return [];
1886
+ }
1887
+ function activeProvider(cfg) {
1888
+ const all = providersOf(cfg);
1889
+ return all.find((x) => x.id === cfg?.activeProviderId) ?? all[0];
1890
+ }
1891
+ function saveProvider(cfg, provider, makeActive) {
1892
+ const all = providersOf(cfg).filter((x) => x.id !== provider.id);
1893
+ all.push(provider);
1894
+ cfg.providers = all;
1895
+ delete cfg.model;
1896
+ delete cfg.apiKey;
1897
+ delete cfg.baseUrl;
1898
+ if (makeActive || !cfg.activeProviderId) cfg.activeProviderId = provider.id;
1899
+ saveConfig(cfg);
1900
+ }
1901
+ function setActiveProvider(cfg, id) {
1902
+ const prov = providersOf(cfg).find((x) => x.id === id);
1903
+ if (!prov) return void 0;
1904
+ cfg.providers = providersOf(cfg);
1905
+ cfg.activeProviderId = id;
1906
+ saveConfig(cfg);
1907
+ return prov;
1908
+ }
1875
1909
  function bail(v) {
1876
1910
  if (p.isCancel(v)) {
1877
1911
  p.cancel("Cancelled.");
@@ -1897,25 +1931,28 @@ async function baseSetup() {
1897
1931
  );
1898
1932
  const pick = MODELS.find((m) => m.value === choice);
1899
1933
  if (!pick) throw new Error(`unknown model choice: ${choice}`);
1900
- const cfg = { agentName, userId: "default" };
1934
+ const cfg = loadConfig() ?? {};
1935
+ cfg.agentName = agentName;
1936
+ cfg.userId ??= "default";
1937
+ let provider;
1901
1938
  if (pick.custom) {
1902
- cfg.model = bail(
1939
+ const model = bail(
1903
1940
  await p.text({ message: "Model id", placeholder: "e.g. MiniMax-M3", validate: (v) => v ? void 0 : "Required" })
1904
1941
  );
1905
- cfg.baseUrl = bail(
1942
+ const baseUrl = bail(
1906
1943
  await p.text({
1907
1944
  message: "Base URL (OpenAI-compatible)",
1908
1945
  placeholder: "https://api.example.com/v1",
1909
1946
  validate: (v) => v && /^https?:\/\//.test(v) ? void 0 : "Must start with http(s)://"
1910
1947
  })
1911
1948
  );
1912
- cfg.apiKey = bail(await p.password({ message: "API key" }));
1949
+ const apiKey = bail(await p.password({ message: "API key" }));
1950
+ provider = { id: model, label: model, model, baseUrl, apiKey };
1913
1951
  } else {
1914
- cfg.model = pick.model;
1915
- if (pick.baseUrl) cfg.baseUrl = pick.baseUrl;
1916
- cfg.apiKey = pick.apiKey ?? (pick.needsKey ? bail(await p.password({ message: "API key" })) : void 0);
1952
+ const apiKey = pick.apiKey ?? (pick.needsKey ? bail(await p.password({ message: "API key" })) : void 0);
1953
+ provider = { id: pick.value, label: pick.label, model: pick.model ?? "", baseUrl: pick.baseUrl, apiKey };
1917
1954
  }
1918
- saveConfig(cfg);
1955
+ saveProvider(cfg, provider, true);
1919
1956
  p.outro(`Saved ${CONFIG} \u2014 run \`thiny\` to start, or \`thiny sui init\` for Sui.`);
1920
1957
  return cfg;
1921
1958
  }
@@ -2352,9 +2389,22 @@ async function runCli() {
2352
2389
  const turn = { inputTokens: 0, outputTokens: 0, toolCalls: 0, modelCalls: 0 };
2353
2390
  const session = { inputTokens: 0, outputTokens: 0, toolCalls: 0, turns: 0 };
2354
2391
  const logger = captureStats(fileLogger, turn);
2355
- const activeModelName = process.env.THINY_MODEL ?? process.env.AGENT_MODEL ?? "openai:gpt-4o-mini";
2356
2392
  const personaName = process.env.THINY_PERSONA_NAME ?? "Thiny";
2357
- const model = loadThinyConfig();
2393
+ const buildModel = (p2) => aiSdkModel({
2394
+ model: p2.model,
2395
+ openai: { baseURL: p2.baseUrl, apiKey: p2.apiKey },
2396
+ anthropic: { apiKey: p2.apiKey }
2397
+ });
2398
+ const startProvider = activeProvider(loadConfig());
2399
+ let activeModel = startProvider ? buildModel(startProvider) : loadThinyConfig();
2400
+ let activeModelName = startProvider?.model ?? process.env.THINY_MODEL ?? process.env.AGENT_MODEL ?? "openai:gpt-4o-mini";
2401
+ const model = {
2402
+ generate: (m, t, s) => activeModel.generate(m, t, s),
2403
+ stream: (m, t, s) => {
2404
+ if (!activeModel.stream) throw new Error("active model has no streaming");
2405
+ return activeModel.stream(m, t, s);
2406
+ }
2407
+ };
2358
2408
  const network = process.env.WALRUS_NETWORK === "mainnet" ? "mainnet" : "testnet";
2359
2409
  const walrus = walrusClient({
2360
2410
  network,
@@ -2725,6 +2775,76 @@ YOUR TOOLS:
2725
2775
  });
2726
2776
  } else memoryRefs.push(ref);
2727
2777
  };
2778
+ const handleConnect = async (arg) => {
2779
+ const cfg = loadConfig() ?? {};
2780
+ const provs = providersOf(cfg);
2781
+ if (provs.length === 0) {
2782
+ renderInfo("No providers configured \u2014 run `thiny init` to add one.");
2783
+ return;
2784
+ }
2785
+ let id = arg;
2786
+ if (!id) {
2787
+ renderInfo("\nProviders:");
2788
+ provs.forEach((pr, i) => {
2789
+ renderInfo(
2790
+ ` ${String(i + 1)}. ${pr.label} (${pr.model})${pr.id === cfg.activeProviderId ? " \xB7 active" : ""}`
2791
+ );
2792
+ });
2793
+ const ans = (await rl.question("Switch to (number, blank to cancel): ")).trim();
2794
+ if (!ans) return;
2795
+ const idx = Number(ans) - 1;
2796
+ const chosen = provs[idx];
2797
+ if (!chosen) {
2798
+ renderWarning("Invalid choice.");
2799
+ return;
2800
+ }
2801
+ id = chosen.id;
2802
+ }
2803
+ const match = provs.find((pr) => pr.id === id || pr.label === id || pr.model === id);
2804
+ const prov = match ? setActiveProvider(cfg, match.id) : void 0;
2805
+ if (!prov) {
2806
+ renderWarning(`No provider "${id}".`);
2807
+ return;
2808
+ }
2809
+ activeModel = buildModel(prov);
2810
+ activeModelName = prov.model;
2811
+ renderInfo(`Connected: ${prov.label} \xB7 ${prov.model}`);
2812
+ };
2813
+ const handleModels = async (arg) => {
2814
+ const cfg = loadConfig() ?? {};
2815
+ const prov = activeProvider(cfg);
2816
+ if (!prov) {
2817
+ renderInfo("No provider configured \u2014 run `thiny init`.");
2818
+ return;
2819
+ }
2820
+ let modelId = arg;
2821
+ if (!modelId) {
2822
+ renderInfo(`
2823
+ Active: ${prov.label} \xB7 current model: ${prov.model}`);
2824
+ renderInfo("Configured providers:");
2825
+ providersOf(cfg).forEach((pr) => {
2826
+ renderInfo(` \u2022 ${pr.label}: ${pr.model}`);
2827
+ });
2828
+ modelId = (await rl.question("New model id for the active provider (blank to cancel): ")).trim();
2829
+ if (!modelId) return;
2830
+ }
2831
+ prov.model = modelId;
2832
+ saveProvider(cfg, prov, true);
2833
+ activeModel = buildModel(prov);
2834
+ activeModelName = modelId;
2835
+ renderInfo(`Model set: ${modelId}`);
2836
+ };
2837
+ const showSlashMenu = () => {
2838
+ renderInfo(
2839
+ "\nCommands: /new \xB7 /connect \xB7 /models \xB7 /tools \xB7 /skills \xB7 /session \xB7 /stats \xB7 /verify <blobId> \xB7 /clear \xB7 /help"
2840
+ );
2841
+ renderInfo(`Tools: ${agent.registry.all().map((t) => t.name).join(", ")}`);
2842
+ const cats = [...defaultRegistry.byCategory()].map(
2843
+ ([cat, defs]) => `${cat}(${defs.map((d) => d.id).join(",")})`
2844
+ );
2845
+ renderInfo(`Skills: ${cats.join(" ")}
2846
+ `);
2847
+ };
2728
2848
  try {
2729
2849
  for (; ; ) {
2730
2850
  for (const ref of memoryRefs.splice(0))
@@ -2738,7 +2858,18 @@ YOUR TOOLS:
2738
2858
  if (trimmed.startsWith("/")) {
2739
2859
  const parts = trimmed.slice(1).split(" ");
2740
2860
  const cmd = parts[0];
2861
+ const arg = parts.slice(1).join(" ").trim() || void 0;
2741
2862
  switch (cmd) {
2863
+ case "":
2864
+ showSlashMenu();
2865
+ break;
2866
+ case "connect":
2867
+ await handleConnect(arg);
2868
+ break;
2869
+ case "models":
2870
+ case "model":
2871
+ await handleModels(arg);
2872
+ break;
2742
2873
  case "new": {
2743
2874
  currentSessionId = `cli-${(/* @__PURE__ */ new Date()).getTime().toString()}`;
2744
2875
  renderInfo("New session started \u2014 long-term memory carries over");
@@ -2809,7 +2940,7 @@ Audit trail ${blobId}
2809
2940
  break;
2810
2941
  case "help":
2811
2942
  renderInfo(
2812
- "\n/new \xB7 /tools \xB7 /skills \xB7 /stats \xB7 /session \xB7 /verify <blobId> \xB7 /clear \xB7 /help\n"
2943
+ "\n/new \xB7 /connect \xB7 /models \xB7 /tools \xB7 /skills \xB7 /stats \xB7 /session \xB7 /verify <blobId> \xB7 /clear \xB7 /help\n(type just `/` to see commands + all tools + skills)\n"
2813
2944
  );
2814
2945
  break;
2815
2946
  default:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinyai",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Thiny AI — a beautiful terminal agent: interactive chat, tools, Walrus memory, and Sui execution.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,17 +37,17 @@
37
37
  "devDependencies": {
38
38
  "tsup": "^8.5.1",
39
39
  "typescript": "^5.5.0",
40
- "@thiny/memory-memwal": "0.1.0",
41
40
  "@thiny/core": "0.1.0",
42
- "@thiny/mcp": "0.1.0",
43
- "@thiny/logger-pino": "0.1.0",
44
41
  "@thiny/model-aisdk": "0.1.0",
42
+ "@thiny/logger-pino": "0.1.0",
43
+ "@thiny/mcp": "0.1.0",
44
+ "@thiny/walrus": "0.1.0",
45
45
  "@thiny/plugin-agents": "0.1.0",
46
46
  "@thiny/plugin-web-search": "0.1.0",
47
- "@thiny/walrus": "0.1.0",
48
47
  "@thiny/signer-sui": "0.1.0",
48
+ "@thiny/plugin-sui": "0.1.0",
49
49
  "@thiny/skills": "0.1.0",
50
- "@thiny/plugin-sui": "0.1.0"
50
+ "@thiny/memory-memwal": "0.1.0"
51
51
  },
52
52
  "author": "Thiny AI",
53
53
  "engines": {