memorix 1.4.0 → 1.4.1

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
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.4.1] - 2026-08-03
6
+
7
+ ### Added
8
+ - **MiniMax M3 video input** -- The bundled `@memorix/ai` provider layer now advertises and routes MiniMax M3 video content through MiniMax's Anthropic-compatible API. Base64 video is covered by focused request-shape tests, and image-only models still receive a clear text fallback instead of an invalid video block. Contributed by [@octo-patch](https://github.com/octo-patch) in #153.
9
+
10
+ ### Changed
11
+ - **Maintained product roadmap** -- Replaced the stale version-by-version roadmap with current product boundaries, operating constraints, and public directions. Release facts now live in this changelog and active maintainer work lives in `ACTIVE_WORK.md`. Contributed by [@FBISiri](https://github.com/FBISiri) in #140.
12
+
13
+ ### Fixed
14
+ - **Deterministic provider tests** -- `@memorix/ai` unit tests no longer discover local API keys or Pi OAuth credentials and unexpectedly call paid, changing provider endpoints. Routine tests are offline by default; deliberate live validation requires `MEMORIX_AI_LIVE_TESTS=1` plus the required credentials.
15
+ - **Stable model metadata assertion** -- Removed a test-only assumption that OpenRouter will permanently list `moonshotai/kimi-k2.6:free`; the bundled catalog snapshot no longer contains that route, while coverage remains for the supported Kimi K2.6 compatibility metadata.
16
+
5
17
  ## [1.4.0] - 2026-08-02
6
18
 
7
19
  ### Changed
package/CLAUDE.md CHANGED
@@ -77,12 +77,12 @@ Use `memorix_resolve` when a task is done or a bug is fixed. This keeps future s
77
77
  | `memorix_rules_sync` | Inspect or sync rules across agents |
78
78
  | `memorix_workspace_sync` | Inspect or migrate workspace integrations |
79
79
 
80
- ## Dev Log
81
-
82
- - **Repository-wide current state**: `docs/dev-log/progress.txt`
83
- - Read that root progress file after the Memory Autopilot step for long-running
84
- release/development work.
85
- - Package-specific historical notes may live under subdirectories such as
86
- `docs/memcode/dev-log/`; treat them as historical unless the current task is
87
- explicitly about that package.
88
- - Update the root progress file when completing substantial cross-session work.
80
+ ## Active Work
81
+
82
+ - **Repository-wide current state**: `ACTIVE_WORK.md`
83
+ - Read that file after the Memory Autopilot step for long-running release or
84
+ development work.
85
+ - It is the only living work-status document. Update it after material
86
+ cross-session work; do not create parallel progress or dev-log files.
87
+ - It must stay public-safe: no local absolute paths, account identifiers,
88
+ credentials, raw chat transcripts, or local tool state.
package/README.md CHANGED
@@ -18,9 +18,9 @@
18
18
  </p>
19
19
 
20
20
  <p align="center">
21
- <a href="https://registry.modelcontextprotocol.io/v0/servers?search=io.github.AVIDS2%2Fmemorix">Listed in the official MCP Registry</a>
21
+ <a href="https://registry.modelcontextprotocol.io/?q=io.github.AVIDS2%2Fmemorix">Listed in the official MCP Registry</a>
22
22
  <br>
23
- <img src="https://mcptoplist.com/badge/io.github.AVIDS2%2Fmemorix.svg" alt="MCP Toplist ranking">
23
+ <a href="https://mcptoplist.com/server/io.github.AVIDS2%2Fmemorix"><img src="https://mcptoplist.com/badge/io.github.AVIDS2%2Fmemorix.svg" alt="View Memorix on MCP Toplist"></a>
24
24
  </p>
25
25
 
26
26
  <p align="center">
@@ -35,11 +35,16 @@
35
35
  <a href="#quick-start">Quick Start</a> |
36
36
  <a href="#memory-model">Memory Model</a> |
37
37
  <a href="#memcode-bundled-terminal-agent">memcode</a> |
38
+ <a href="ACTIVE_WORK.md">Active Work</a> |
38
39
  <a href="#docs">Docs</a>
39
40
  </p>
40
41
 
41
42
  ---
42
43
 
44
+ > Maintainer status and the current public work boundary live in
45
+ > [ACTIVE_WORK.md](ACTIVE_WORK.md). It is the repository's single living work
46
+ > tracker.
47
+
43
48
  <h2 id="what-memorix-is"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/section-overview.svg"><img src="assets/tags/section-overview.svg" alt="Memorix" height="32" /></picture></h2>
44
49
 
45
50
  Memorix gives the AI coding agents you already use a shared, searchable project memory that survives new chats, IDE switches, terminal sessions, and handoffs. The memory lives under the Git project, not inside one chat window or one tool.
package/README.zh-CN.md CHANGED
@@ -18,9 +18,9 @@
18
18
  </p>
19
19
 
20
20
  <p align="center">
21
- <a href="https://registry.modelcontextprotocol.io/v0/servers?search=io.github.AVIDS2%2Fmemorix">已收录至官方 MCP Registry</a>
21
+ <a href="https://registry.modelcontextprotocol.io/?q=io.github.AVIDS2%2Fmemorix">已收录至官方 MCP Registry</a>
22
22
  <br>
23
- <img src="https://mcptoplist.com/badge/io.github.AVIDS2%2Fmemorix.svg" alt="MCP Toplist ranking">
23
+ <a href="https://mcptoplist.com/server/io.github.AVIDS2%2Fmemorix"><img src="https://mcptoplist.com/badge/io.github.AVIDS2%2Fmemorix.svg" alt="在 MCP Toplist 查看 Memorix"></a>
24
24
  </p>
25
25
 
26
26
  <p align="center">
@@ -35,11 +35,15 @@
35
35
  <a href="#快速开始">快速开始</a> |
36
36
  <a href="#记忆模型">记忆模型</a> |
37
37
  <a href="#memcode内置终端-agent">memcode</a> |
38
+ <a href="ACTIVE_WORK.md">当前工作</a> |
38
39
  <a href="#文档">文档</a>
39
40
  </p>
40
41
 
41
42
  ---
42
43
 
44
+ > 维护者当前工作状态和公开边界统一记录在
45
+ > [ACTIVE_WORK.md](ACTIVE_WORK.md),这是仓库唯一的活动工作文档。
46
+
43
47
  <h2 id="memorix-是什么"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/section-overview.svg"><img src="assets/tags/section-overview.svg" alt="Memorix" height="32" /></picture></h2>
44
48
 
45
49
  Memorix 给你已经在用的 AI 编程 Agent 加上一套共享、可检索的项目记忆,让它跨越新对话、切换 IDE、重开终端 session 和交接都不丢失。记忆归属于 Git 项目,不会只困在某个聊天窗口或工具里。
package/dist/cli/index.js CHANGED
@@ -3221,7 +3221,7 @@ ${import_picocolors.default.gray(m3)} ${s3}
3221
3221
 
3222
3222
  // src/cli/version.ts
3223
3223
  function getCliVersion() {
3224
- return true ? "1.4.0" : pkg.version;
3224
+ return true ? "1.4.1" : pkg.version;
3225
3225
  }
3226
3226
  var init_version = __esm({
3227
3227
  "src/cli/version.ts"() {
@@ -42894,7 +42894,7 @@ var init_models_generated = __esm({
42894
42894
  provider: "minimax",
42895
42895
  baseUrl: "https://api.minimax.io/anthropic",
42896
42896
  reasoning: true,
42897
- input: ["text", "image"],
42897
+ input: ["text", "image", "video"],
42898
42898
  cost: {
42899
42899
  input: 0.3,
42900
42900
  output: 1.2,
@@ -42947,7 +42947,7 @@ var init_models_generated = __esm({
42947
42947
  provider: "minimax-cn",
42948
42948
  baseUrl: "https://api.minimaxi.com/anthropic",
42949
42949
  reasoning: true,
42950
- input: ["text", "image"],
42950
+ input: ["text", "image", "video"],
42951
42951
  cost: {
42952
42952
  input: 0.3,
42953
42953
  output: 1.2,
@@ -62222,11 +62222,11 @@ var init_simple_options = __esm({
62222
62222
  });
62223
62223
 
62224
62224
  // packages/ai/dist/providers/transform-messages.js
62225
- function replaceImagesWithPlaceholder(content, placeholder) {
62225
+ function replaceMediaWithPlaceholder(content, dropType, placeholder) {
62226
62226
  const result = [];
62227
62227
  let previousWasPlaceholder = false;
62228
62228
  for (const block of content) {
62229
- if (block.type === "image") {
62229
+ if (block.type === dropType) {
62230
62230
  if (!previousWasPlaceholder) {
62231
62231
  result.push({ type: "text", text: placeholder });
62232
62232
  }
@@ -62234,33 +62234,39 @@ function replaceImagesWithPlaceholder(content, placeholder) {
62234
62234
  continue;
62235
62235
  }
62236
62236
  result.push(block);
62237
- previousWasPlaceholder = block.text === placeholder;
62237
+ previousWasPlaceholder = block.type === "text" && block.text === placeholder;
62238
62238
  }
62239
62239
  return result;
62240
62240
  }
62241
- function downgradeUnsupportedImages(messages, model) {
62242
- if (model.input.includes("image")) {
62241
+ function downgradeUnsupportedMedia(messages, model) {
62242
+ const supportsImage = model.input.includes("image");
62243
+ const supportsVideo = model.input.includes("video");
62244
+ if (supportsImage && supportsVideo) {
62243
62245
  return messages;
62244
62246
  }
62245
62247
  return messages.map((msg) => {
62246
62248
  if (msg.role === "user" && Array.isArray(msg.content)) {
62247
- return {
62248
- ...msg,
62249
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER)
62250
- };
62249
+ let content = msg.content;
62250
+ if (!supportsImage)
62251
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_USER_IMAGE_PLACEHOLDER);
62252
+ if (!supportsVideo)
62253
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_USER_VIDEO_PLACEHOLDER);
62254
+ return { ...msg, content };
62251
62255
  }
62252
62256
  if (msg.role === "toolResult") {
62253
- return {
62254
- ...msg,
62255
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER)
62256
- };
62257
+ let content = msg.content;
62258
+ if (!supportsImage)
62259
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_TOOL_IMAGE_PLACEHOLDER);
62260
+ if (!supportsVideo)
62261
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_TOOL_VIDEO_PLACEHOLDER);
62262
+ return { ...msg, content };
62257
62263
  }
62258
62264
  return msg;
62259
62265
  });
62260
62266
  }
62261
62267
  function transformMessages(messages, model, normalizeToolCallId2) {
62262
62268
  const toolCallIdMap = /* @__PURE__ */ new Map();
62263
- const imageAwareMessages = downgradeUnsupportedImages(messages, model);
62269
+ const imageAwareMessages = downgradeUnsupportedMedia(messages, model);
62264
62270
  const transformed = imageAwareMessages.map((msg) => {
62265
62271
  if (msg.role === "user") {
62266
62272
  return msg;
@@ -62372,13 +62378,15 @@ function transformMessages(messages, model, normalizeToolCallId2) {
62372
62378
  insertSyntheticToolResults();
62373
62379
  return result;
62374
62380
  }
62375
- var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER;
62381
+ var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER, NON_VISION_USER_VIDEO_PLACEHOLDER, NON_VISION_TOOL_VIDEO_PLACEHOLDER;
62376
62382
  var init_transform_messages = __esm({
62377
62383
  "packages/ai/dist/providers/transform-messages.js"() {
62378
62384
  "use strict";
62379
62385
  init_esm_shims();
62380
62386
  NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
62381
62387
  NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
62388
+ NON_VISION_USER_VIDEO_PLACEHOLDER = "(video omitted: model does not support video)";
62389
+ NON_VISION_TOOL_VIDEO_PLACEHOLDER = "(tool video omitted: model does not support video)";
62382
62390
  }
62383
62391
  });
62384
62392
 
@@ -62409,8 +62417,8 @@ function getCacheControl(model, cacheRetention) {
62409
62417
  };
62410
62418
  }
62411
62419
  function convertContentBlocks(content) {
62412
- const hasImages = content.some((c5) => c5.type === "image");
62413
- if (!hasImages) {
62420
+ const hasMedia = content.some((c5) => c5.type === "image" || c5.type === "video");
62421
+ if (!hasMedia) {
62414
62422
  return sanitizeSurrogates(content.map((c5) => c5.text).join("\n"));
62415
62423
  }
62416
62424
  const blocks = content.map((block) => {
@@ -62420,6 +62428,16 @@ function convertContentBlocks(content) {
62420
62428
  text: sanitizeSurrogates(block.text)
62421
62429
  };
62422
62430
  }
62431
+ if (block.type === "video") {
62432
+ return {
62433
+ type: "video",
62434
+ source: {
62435
+ type: "base64",
62436
+ media_type: block.mimeType,
62437
+ data: block.data
62438
+ }
62439
+ };
62440
+ }
62423
62441
  return {
62424
62442
  type: "image",
62425
62443
  source: {
@@ -62433,7 +62451,7 @@ function convertContentBlocks(content) {
62433
62451
  if (!hasText) {
62434
62452
  blocks.unshift({
62435
62453
  type: "text",
62436
- text: "(see attached image)"
62454
+ text: "(see attached media)"
62437
62455
  });
62438
62456
  }
62439
62457
  return blocks;
@@ -62783,6 +62801,15 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
62783
62801
  type: "text",
62784
62802
  text: sanitizeSurrogates(item.text)
62785
62803
  };
62804
+ } else if (item.type === "video") {
62805
+ return {
62806
+ type: "video",
62807
+ source: {
62808
+ type: "base64",
62809
+ media_type: item.mimeType,
62810
+ data: item.data
62811
+ }
62812
+ };
62786
62813
  } else {
62787
62814
  return {
62788
62815
  type: "image",
@@ -62863,6 +62890,8 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
62863
62890
  toolResults.push({
62864
62891
  type: "tool_result",
62865
62892
  tool_use_id: msg.toolCallId,
62893
+ // MiniMax's Anthropic-compatible API accepts video in tool results;
62894
+ // the SDK's ToolResultBlockParam.content type predates video support.
62866
62895
  content: convertContentBlocks(msg.content),
62867
62896
  is_error: msg.isError
62868
62897
  });
@@ -62889,7 +62918,7 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
62889
62918
  if (lastMessage.role === "user") {
62890
62919
  if (Array.isArray(lastMessage.content)) {
62891
62920
  const lastBlock = lastMessage.content[lastMessage.content.length - 1];
62892
- if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "tool_result")) {
62921
+ if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "video" || lastBlock.type === "tool_result")) {
62893
62922
  lastBlock.cache_control = cacheControl;
62894
62923
  }
62895
62924
  } else if (typeof lastMessage.content === "string") {
@@ -189639,6 +189668,7 @@ function compareDateStrings(a3, b3) {
189639
189668
  }
189640
189669
  function detectStaleProgressNotes(input) {
189641
189670
  const candidates = [
189671
+ "ACTIVE_WORK.md",
189642
189672
  "progress.txt",
189643
189673
  "docs/dev-log/progress.txt",
189644
189674
  "docs/memcode/dev-log/progress.txt"
@@ -213306,7 +213336,7 @@ The path should point to a directory containing a .git folder.`
213306
213336
  };
213307
213337
  const server = existingServer ?? new McpServer({
213308
213338
  name: "memorix",
213309
- version: true ? "1.4.0" : "1.0.1"
213339
+ version: true ? "1.4.1" : "1.0.1"
213310
213340
  });
213311
213341
  const originalRegisterTool = server.registerTool.bind(server);
213312
213342
  server.registerTool = ((name, ...args) => {
package/dist/index.js CHANGED
@@ -32930,7 +32930,7 @@ var init_models_generated = __esm({
32930
32930
  provider: "minimax",
32931
32931
  baseUrl: "https://api.minimax.io/anthropic",
32932
32932
  reasoning: true,
32933
- input: ["text", "image"],
32933
+ input: ["text", "image", "video"],
32934
32934
  cost: {
32935
32935
  input: 0.3,
32936
32936
  output: 1.2,
@@ -32983,7 +32983,7 @@ var init_models_generated = __esm({
32983
32983
  provider: "minimax-cn",
32984
32984
  baseUrl: "https://api.minimaxi.com/anthropic",
32985
32985
  reasoning: true,
32986
- input: ["text", "image"],
32986
+ input: ["text", "image", "video"],
32987
32987
  cost: {
32988
32988
  input: 0.3,
32989
32989
  output: 1.2,
@@ -52258,11 +52258,11 @@ var init_simple_options = __esm({
52258
52258
  });
52259
52259
 
52260
52260
  // packages/ai/dist/providers/transform-messages.js
52261
- function replaceImagesWithPlaceholder(content, placeholder) {
52261
+ function replaceMediaWithPlaceholder(content, dropType, placeholder) {
52262
52262
  const result = [];
52263
52263
  let previousWasPlaceholder = false;
52264
52264
  for (const block of content) {
52265
- if (block.type === "image") {
52265
+ if (block.type === dropType) {
52266
52266
  if (!previousWasPlaceholder) {
52267
52267
  result.push({ type: "text", text: placeholder });
52268
52268
  }
@@ -52270,33 +52270,39 @@ function replaceImagesWithPlaceholder(content, placeholder) {
52270
52270
  continue;
52271
52271
  }
52272
52272
  result.push(block);
52273
- previousWasPlaceholder = block.text === placeholder;
52273
+ previousWasPlaceholder = block.type === "text" && block.text === placeholder;
52274
52274
  }
52275
52275
  return result;
52276
52276
  }
52277
- function downgradeUnsupportedImages(messages, model) {
52278
- if (model.input.includes("image")) {
52277
+ function downgradeUnsupportedMedia(messages, model) {
52278
+ const supportsImage = model.input.includes("image");
52279
+ const supportsVideo = model.input.includes("video");
52280
+ if (supportsImage && supportsVideo) {
52279
52281
  return messages;
52280
52282
  }
52281
52283
  return messages.map((msg) => {
52282
52284
  if (msg.role === "user" && Array.isArray(msg.content)) {
52283
- return {
52284
- ...msg,
52285
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER)
52286
- };
52285
+ let content = msg.content;
52286
+ if (!supportsImage)
52287
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_USER_IMAGE_PLACEHOLDER);
52288
+ if (!supportsVideo)
52289
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_USER_VIDEO_PLACEHOLDER);
52290
+ return { ...msg, content };
52287
52291
  }
52288
52292
  if (msg.role === "toolResult") {
52289
- return {
52290
- ...msg,
52291
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER)
52292
- };
52293
+ let content = msg.content;
52294
+ if (!supportsImage)
52295
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_TOOL_IMAGE_PLACEHOLDER);
52296
+ if (!supportsVideo)
52297
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_TOOL_VIDEO_PLACEHOLDER);
52298
+ return { ...msg, content };
52293
52299
  }
52294
52300
  return msg;
52295
52301
  });
52296
52302
  }
52297
52303
  function transformMessages(messages, model, normalizeToolCallId2) {
52298
52304
  const toolCallIdMap = /* @__PURE__ */ new Map();
52299
- const imageAwareMessages = downgradeUnsupportedImages(messages, model);
52305
+ const imageAwareMessages = downgradeUnsupportedMedia(messages, model);
52300
52306
  const transformed = imageAwareMessages.map((msg) => {
52301
52307
  if (msg.role === "user") {
52302
52308
  return msg;
@@ -52408,13 +52414,15 @@ function transformMessages(messages, model, normalizeToolCallId2) {
52408
52414
  insertSyntheticToolResults();
52409
52415
  return result;
52410
52416
  }
52411
- var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER;
52417
+ var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER, NON_VISION_USER_VIDEO_PLACEHOLDER, NON_VISION_TOOL_VIDEO_PLACEHOLDER;
52412
52418
  var init_transform_messages = __esm({
52413
52419
  "packages/ai/dist/providers/transform-messages.js"() {
52414
52420
  "use strict";
52415
52421
  init_esm_shims();
52416
52422
  NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
52417
52423
  NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
52424
+ NON_VISION_USER_VIDEO_PLACEHOLDER = "(video omitted: model does not support video)";
52425
+ NON_VISION_TOOL_VIDEO_PLACEHOLDER = "(tool video omitted: model does not support video)";
52418
52426
  }
52419
52427
  });
52420
52428
 
@@ -52445,8 +52453,8 @@ function getCacheControl(model, cacheRetention) {
52445
52453
  };
52446
52454
  }
52447
52455
  function convertContentBlocks(content) {
52448
- const hasImages = content.some((c) => c.type === "image");
52449
- if (!hasImages) {
52456
+ const hasMedia = content.some((c) => c.type === "image" || c.type === "video");
52457
+ if (!hasMedia) {
52450
52458
  return sanitizeSurrogates(content.map((c) => c.text).join("\n"));
52451
52459
  }
52452
52460
  const blocks = content.map((block) => {
@@ -52456,6 +52464,16 @@ function convertContentBlocks(content) {
52456
52464
  text: sanitizeSurrogates(block.text)
52457
52465
  };
52458
52466
  }
52467
+ if (block.type === "video") {
52468
+ return {
52469
+ type: "video",
52470
+ source: {
52471
+ type: "base64",
52472
+ media_type: block.mimeType,
52473
+ data: block.data
52474
+ }
52475
+ };
52476
+ }
52459
52477
  return {
52460
52478
  type: "image",
52461
52479
  source: {
@@ -52469,7 +52487,7 @@ function convertContentBlocks(content) {
52469
52487
  if (!hasText) {
52470
52488
  blocks.unshift({
52471
52489
  type: "text",
52472
- text: "(see attached image)"
52490
+ text: "(see attached media)"
52473
52491
  });
52474
52492
  }
52475
52493
  return blocks;
@@ -52819,6 +52837,15 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
52819
52837
  type: "text",
52820
52838
  text: sanitizeSurrogates(item.text)
52821
52839
  };
52840
+ } else if (item.type === "video") {
52841
+ return {
52842
+ type: "video",
52843
+ source: {
52844
+ type: "base64",
52845
+ media_type: item.mimeType,
52846
+ data: item.data
52847
+ }
52848
+ };
52822
52849
  } else {
52823
52850
  return {
52824
52851
  type: "image",
@@ -52899,6 +52926,8 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
52899
52926
  toolResults.push({
52900
52927
  type: "tool_result",
52901
52928
  tool_use_id: msg.toolCallId,
52929
+ // MiniMax's Anthropic-compatible API accepts video in tool results;
52930
+ // the SDK's ToolResultBlockParam.content type predates video support.
52902
52931
  content: convertContentBlocks(msg.content),
52903
52932
  is_error: msg.isError
52904
52933
  });
@@ -52925,7 +52954,7 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
52925
52954
  if (lastMessage.role === "user") {
52926
52955
  if (Array.isArray(lastMessage.content)) {
52927
52956
  const lastBlock = lastMessage.content[lastMessage.content.length - 1];
52928
- if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "tool_result")) {
52957
+ if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "video" || lastBlock.type === "tool_result")) {
52929
52958
  lastBlock.cache_control = cacheControl;
52930
52959
  }
52931
52960
  } else if (typeof lastMessage.content === "string") {
@@ -156516,6 +156545,7 @@ function compareDateStrings(a, b) {
156516
156545
  }
156517
156546
  function detectStaleProgressNotes(input) {
156518
156547
  const candidates = [
156548
+ "ACTIVE_WORK.md",
156519
156549
  "progress.txt",
156520
156550
  "docs/dev-log/progress.txt",
156521
156551
  "docs/memcode/dev-log/progress.txt"
@@ -164315,7 +164345,7 @@ The path should point to a directory containing a .git folder.`
164315
164345
  };
164316
164346
  const server = existingServer ?? new McpServer({
164317
164347
  name: "memorix",
164318
- version: true ? "1.4.0" : "1.0.1"
164348
+ version: true ? "1.4.1" : "1.0.1"
164319
164349
  });
164320
164350
  const originalRegisterTool = server.registerTool.bind(server);
164321
164351
  server.registerTool = ((name, ...args) => {
@@ -168580,7 +168610,7 @@ var init_serve_shared = __esm({
168580
168610
 
168581
168611
  // src/cli/version.ts
168582
168612
  function getCliVersion() {
168583
- return true ? "1.4.0" : pkg.version;
168613
+ return true ? "1.4.1" : pkg.version;
168584
168614
  }
168585
168615
  var init_version3 = __esm({
168586
168616
  "src/cli/version.ts"() {
@@ -31308,7 +31308,7 @@ var init_models_generated = __esm({
31308
31308
  provider: "minimax",
31309
31309
  baseUrl: "https://api.minimax.io/anthropic",
31310
31310
  reasoning: true,
31311
- input: ["text", "image"],
31311
+ input: ["text", "image", "video"],
31312
31312
  cost: {
31313
31313
  input: 0.3,
31314
31314
  output: 1.2,
@@ -31361,7 +31361,7 @@ var init_models_generated = __esm({
31361
31361
  provider: "minimax-cn",
31362
31362
  baseUrl: "https://api.minimaxi.com/anthropic",
31363
31363
  reasoning: true,
31364
- input: ["text", "image"],
31364
+ input: ["text", "image", "video"],
31365
31365
  cost: {
31366
31366
  input: 0.3,
31367
31367
  output: 1.2,
@@ -50636,11 +50636,11 @@ var init_simple_options = __esm({
50636
50636
  });
50637
50637
 
50638
50638
  // packages/ai/dist/providers/transform-messages.js
50639
- function replaceImagesWithPlaceholder(content, placeholder) {
50639
+ function replaceMediaWithPlaceholder(content, dropType, placeholder) {
50640
50640
  const result = [];
50641
50641
  let previousWasPlaceholder = false;
50642
50642
  for (const block of content) {
50643
- if (block.type === "image") {
50643
+ if (block.type === dropType) {
50644
50644
  if (!previousWasPlaceholder) {
50645
50645
  result.push({ type: "text", text: placeholder });
50646
50646
  }
@@ -50648,33 +50648,39 @@ function replaceImagesWithPlaceholder(content, placeholder) {
50648
50648
  continue;
50649
50649
  }
50650
50650
  result.push(block);
50651
- previousWasPlaceholder = block.text === placeholder;
50651
+ previousWasPlaceholder = block.type === "text" && block.text === placeholder;
50652
50652
  }
50653
50653
  return result;
50654
50654
  }
50655
- function downgradeUnsupportedImages(messages, model) {
50656
- if (model.input.includes("image")) {
50655
+ function downgradeUnsupportedMedia(messages, model) {
50656
+ const supportsImage = model.input.includes("image");
50657
+ const supportsVideo = model.input.includes("video");
50658
+ if (supportsImage && supportsVideo) {
50657
50659
  return messages;
50658
50660
  }
50659
50661
  return messages.map((msg) => {
50660
50662
  if (msg.role === "user" && Array.isArray(msg.content)) {
50661
- return {
50662
- ...msg,
50663
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER)
50664
- };
50663
+ let content = msg.content;
50664
+ if (!supportsImage)
50665
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_USER_IMAGE_PLACEHOLDER);
50666
+ if (!supportsVideo)
50667
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_USER_VIDEO_PLACEHOLDER);
50668
+ return { ...msg, content };
50665
50669
  }
50666
50670
  if (msg.role === "toolResult") {
50667
- return {
50668
- ...msg,
50669
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER)
50670
- };
50671
+ let content = msg.content;
50672
+ if (!supportsImage)
50673
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_TOOL_IMAGE_PLACEHOLDER);
50674
+ if (!supportsVideo)
50675
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_TOOL_VIDEO_PLACEHOLDER);
50676
+ return { ...msg, content };
50671
50677
  }
50672
50678
  return msg;
50673
50679
  });
50674
50680
  }
50675
50681
  function transformMessages(messages, model, normalizeToolCallId2) {
50676
50682
  const toolCallIdMap = /* @__PURE__ */ new Map();
50677
- const imageAwareMessages = downgradeUnsupportedImages(messages, model);
50683
+ const imageAwareMessages = downgradeUnsupportedMedia(messages, model);
50678
50684
  const transformed = imageAwareMessages.map((msg) => {
50679
50685
  if (msg.role === "user") {
50680
50686
  return msg;
@@ -50786,13 +50792,15 @@ function transformMessages(messages, model, normalizeToolCallId2) {
50786
50792
  insertSyntheticToolResults();
50787
50793
  return result;
50788
50794
  }
50789
- var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER;
50795
+ var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER, NON_VISION_USER_VIDEO_PLACEHOLDER, NON_VISION_TOOL_VIDEO_PLACEHOLDER;
50790
50796
  var init_transform_messages = __esm({
50791
50797
  "packages/ai/dist/providers/transform-messages.js"() {
50792
50798
  "use strict";
50793
50799
  init_esm_shims();
50794
50800
  NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
50795
50801
  NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
50802
+ NON_VISION_USER_VIDEO_PLACEHOLDER = "(video omitted: model does not support video)";
50803
+ NON_VISION_TOOL_VIDEO_PLACEHOLDER = "(tool video omitted: model does not support video)";
50796
50804
  }
50797
50805
  });
50798
50806
 
@@ -50823,8 +50831,8 @@ function getCacheControl(model, cacheRetention) {
50823
50831
  };
50824
50832
  }
50825
50833
  function convertContentBlocks(content) {
50826
- const hasImages = content.some((c) => c.type === "image");
50827
- if (!hasImages) {
50834
+ const hasMedia = content.some((c) => c.type === "image" || c.type === "video");
50835
+ if (!hasMedia) {
50828
50836
  return sanitizeSurrogates(content.map((c) => c.text).join("\n"));
50829
50837
  }
50830
50838
  const blocks = content.map((block) => {
@@ -50834,6 +50842,16 @@ function convertContentBlocks(content) {
50834
50842
  text: sanitizeSurrogates(block.text)
50835
50843
  };
50836
50844
  }
50845
+ if (block.type === "video") {
50846
+ return {
50847
+ type: "video",
50848
+ source: {
50849
+ type: "base64",
50850
+ media_type: block.mimeType,
50851
+ data: block.data
50852
+ }
50853
+ };
50854
+ }
50837
50855
  return {
50838
50856
  type: "image",
50839
50857
  source: {
@@ -50847,7 +50865,7 @@ function convertContentBlocks(content) {
50847
50865
  if (!hasText) {
50848
50866
  blocks.unshift({
50849
50867
  type: "text",
50850
- text: "(see attached image)"
50868
+ text: "(see attached media)"
50851
50869
  });
50852
50870
  }
50853
50871
  return blocks;
@@ -51197,6 +51215,15 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
51197
51215
  type: "text",
51198
51216
  text: sanitizeSurrogates(item.text)
51199
51217
  };
51218
+ } else if (item.type === "video") {
51219
+ return {
51220
+ type: "video",
51221
+ source: {
51222
+ type: "base64",
51223
+ media_type: item.mimeType,
51224
+ data: item.data
51225
+ }
51226
+ };
51200
51227
  } else {
51201
51228
  return {
51202
51229
  type: "image",
@@ -51277,6 +51304,8 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
51277
51304
  toolResults.push({
51278
51305
  type: "tool_result",
51279
51306
  tool_use_id: msg.toolCallId,
51307
+ // MiniMax's Anthropic-compatible API accepts video in tool results;
51308
+ // the SDK's ToolResultBlockParam.content type predates video support.
51280
51309
  content: convertContentBlocks(msg.content),
51281
51310
  is_error: msg.isError
51282
51311
  });
@@ -51303,7 +51332,7 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
51303
51332
  if (lastMessage.role === "user") {
51304
51333
  if (Array.isArray(lastMessage.content)) {
51305
51334
  const lastBlock = lastMessage.content[lastMessage.content.length - 1];
51306
- if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "tool_result")) {
51335
+ if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "video" || lastBlock.type === "tool_result")) {
51307
51336
  lastBlock.cache_control = cacheControl;
51308
51337
  }
51309
51338
  } else if (typeof lastMessage.content === "string") {