@femtomc/mu-agent 26.3.1 → 26.3.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,KAAK,EAAmB,MAAM,kBAAkB,CAAC;AAI5E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAmB,KAAK,mBAAmB,EAAE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AAEtE,MAAM,MAAM,gCAAgC,GAAG;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uBAAuB,EAAE,MAAM,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,eAAe,GAAG,gCAAgC,CAAC;AACxD,KAAK,eAAe,GAAG,gCAAgC,CAAC;AAQxD,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAgCxC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAIpF,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAW1C,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAExF,MAAM,MAAM,wBAAwB,GAAG;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,EAAE,eAAe,CAAC;CACzB,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACxC,OAAO,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC7E,YAAY,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAC7D,OAAO,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAED,MAAM,MAAM,gBAAgB,GACzB;IACA,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACtB,GACD;IACA,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACtB,GACD;IACA,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EACH,mBAAmB,GACnB,4BAA4B,GAC5B,yBAAyB,GACzB,oBAAoB,GACpB,iBAAiB,GACjB,mBAAmB,GACnB,sBAAsB,GACtB,uBAAuB,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACtB,CAAC;AAEL,MAAM,MAAM,yBAAyB,GAAG;IACvC,eAAe,CAAC,EAAE,sBAAsB,CAAC;CACzC,CAAC;AAMF,qBAAa,qBAAqB;;gBAGd,IAAI,GAAE,yBAA8B;IAIhD,OAAO,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,uBAAuB,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,GACjF;QACA,IAAI,EAAE,UAAU,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;KACnB,GACD;QACA,IAAI,EAAE,QAAQ,CAAC;QACf,MAAM,EACH,4BAA4B,GAC5B,iBAAiB,GACjB,mBAAmB,GACnB,sBAAsB,GACtB,uBAAuB,CAAC;QAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;KAChB;CAyGJ;AAED,MAAM,MAAM,yCAAyC,GAAG;IACvD,YAAY,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;IAClF,YAAY,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACnF,IAAI,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IAC1C,OAAO,EAAE,wBAAwB,CAAC;IAClC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,MAAM,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;IAC7B,wBAAwB,CAAC,EAAE,yCAAyC,CAAC;CACrE,CAAC;AAwRF,qBAAa,gCAAiC,YAAW,yCAAyC;;gBAM9E,IAAI,EAAE,MAAM;IAuDlB,YAAY,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAK7D,YAAY,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUvE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGlC;AAED,qBAAa,wBAAwB;;gBAWjB,IAAI,EAAE,4BAA4B;IAgExC,aAAa,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,eAAe,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmHtG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAMlC;AAED,MAAM,MAAM,8BAA8B,GAAG;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACnE,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CACrD,CAAC;AAEF,OAAO,EAAE,8BAA8B,EAAE,CAAC;AAgG1C,qBAAa,0BAA2B,YAAW,wBAAwB;;gBAkBvD,IAAI,GAAE,8BAAmC;IAgO/C,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqBjD,OAAO,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAmJlF,OAAO,IAAI,IAAI;CAKtB"}
package/dist/operator.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { UiDocSchema, normalizeUiDocs } from "@femtomc/mu-core";
2
2
  import { appendJsonl, getStorePaths } from "@femtomc/mu-core/node";
3
3
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
4
- import { dirname, join } from "node:path";
4
+ import { dirname, isAbsolute, join } from "node:path";
5
5
  import { z } from "zod";
6
6
  import { CommandContextResolver } from "./command_context.js";
7
7
  import { createMuSession } from "./session_factory.js";
@@ -173,16 +173,43 @@ function defaultSessionId() {
173
173
  function defaultTurnId() {
174
174
  return `turn-${crypto.randomUUID()}`;
175
175
  }
176
+ function classifyProviderFailureCodeFromMessage(message) {
177
+ if (!message) {
178
+ return null;
179
+ }
180
+ const normalized = message.trim().toLowerCase();
181
+ if (!normalized) {
182
+ return null;
183
+ }
184
+ if (normalized.includes("chatgpt usage limit") ||
185
+ normalized.includes("usage limit") ||
186
+ normalized.includes("insufficient_quota") ||
187
+ normalized.includes("quota exceeded") ||
188
+ normalized.includes("billing hard limit")) {
189
+ return "operator_provider_usage_limit";
190
+ }
191
+ if (normalized.includes("context_length_exceeded") ||
192
+ normalized.includes("context window") ||
193
+ normalized.includes("maximum context length") ||
194
+ normalized.includes("input exceeds the context window")) {
195
+ return "operator_provider_context_length_exceeded";
196
+ }
197
+ return null;
198
+ }
176
199
  function buildOperatorFailureFallbackMessage(code) {
177
200
  const reasonLine = code === "operator_timeout"
178
201
  ? "The operator turn exceeded the messaging timeout before a safe response was produced."
179
202
  : code === "operator_busy"
180
203
  ? "Another operator turn is already in progress for this conversation."
181
- : code === "operator_empty_response"
182
- ? "The operator completed without a usable response payload."
183
- : code === "operator_cancelled"
184
- ? "The operator turn was cancelled before completion."
185
- : "An internal operator runtime/formatting error interrupted the turn.";
204
+ : code === "operator_provider_usage_limit"
205
+ ? "The configured operator provider rejected the turn due to usage or quota limits."
206
+ : code === "operator_provider_context_length_exceeded"
207
+ ? "The configured operator provider rejected the turn because the context window was exceeded."
208
+ : code === "operator_empty_response"
209
+ ? "The operator completed without a usable response payload."
210
+ : code === "operator_cancelled"
211
+ ? "The operator turn was cancelled before completion."
212
+ : "An internal operator runtime/formatting error interrupted the turn.";
186
213
  return [
187
214
  "I could not complete that turn safely.",
188
215
  `Code: ${code}`,
@@ -198,6 +225,16 @@ function classifyBackendFailureCode(err) {
198
225
  if (message.includes("pi operator timeout") || message.includes("operator timeout")) {
199
226
  return "operator_timeout";
200
227
  }
228
+ if (message.includes("operator_provider_usage_limit")) {
229
+ return "operator_provider_usage_limit";
230
+ }
231
+ if (message.includes("operator_provider_context_length_exceeded")) {
232
+ return "operator_provider_context_length_exceeded";
233
+ }
234
+ const providerFailureCode = classifyProviderFailureCodeFromMessage(message);
235
+ if (providerFailureCode) {
236
+ return providerFailureCode;
237
+ }
201
238
  if (message.includes("operator_empty_response")) {
202
239
  return "operator_empty_response";
203
240
  }
@@ -255,6 +292,13 @@ function nonEmptyString(value) {
255
292
  const trimmed = value.trim();
256
293
  return trimmed.length > 0 ? trimmed : null;
257
294
  }
295
+ function autonomousSessionIdOverride(metadata) {
296
+ const source = nonEmptyString(metadata.source);
297
+ if (source !== "autonomous_ingress") {
298
+ return null;
299
+ }
300
+ return nonEmptyString(metadata.operator_session_id);
301
+ }
258
302
  function autonomousTurnEnvironment(metadata) {
259
303
  const source = nonEmptyString(metadata.source);
260
304
  if (source !== "autonomous_ingress") {
@@ -281,6 +325,38 @@ function autonomousTurnEnvironment(metadata) {
281
325
  }
282
326
  return out;
283
327
  }
328
+ function resolveRepoPath(repoRoot, candidate) {
329
+ return isAbsolute(candidate) ? candidate : join(repoRoot, candidate);
330
+ }
331
+ function autonomousOperatorSessionOverrides(metadata, repoRoot) {
332
+ const source = nonEmptyString(metadata.source);
333
+ if (source !== "autonomous_ingress") {
334
+ return {};
335
+ }
336
+ const provider = nonEmptyString(metadata.operator_provider);
337
+ const model = nonEmptyString(metadata.operator_model);
338
+ const thinking = nonEmptyString(metadata.operator_thinking);
339
+ const sessionFileRaw = nonEmptyString(metadata.operator_session_file);
340
+ const sessionDirRaw = nonEmptyString(metadata.operator_session_dir);
341
+ const sessionFile = sessionFileRaw ? resolveRepoPath(repoRoot, sessionFileRaw) : undefined;
342
+ const sessionDir = sessionDirRaw ? resolveRepoPath(repoRoot, sessionDirRaw) : undefined;
343
+ return {
344
+ ...(provider ? { provider } : {}),
345
+ ...(model ? { model } : {}),
346
+ ...(thinking ? { thinking } : {}),
347
+ ...(sessionFile ? { sessionFile } : {}),
348
+ ...(sessionDir ? { sessionDir } : {}),
349
+ };
350
+ }
351
+ function operatorSessionProfileKey(opts) {
352
+ return JSON.stringify({
353
+ provider: opts.provider ?? null,
354
+ model: opts.model ?? null,
355
+ thinking: opts.thinking ?? null,
356
+ sessionFile: opts.sessionFile ?? null,
357
+ sessionDir: opts.sessionDir ?? null,
358
+ });
359
+ }
284
360
  function isUiToolName(toolName) {
285
361
  const normalized = toolName.trim().toLowerCase();
286
362
  return normalized === "mu_ui";
@@ -411,6 +487,10 @@ export class MessagingOperatorRuntime {
411
487
  this.#conversationSessionStore = opts.conversationSessionStore ?? null;
412
488
  }
413
489
  async #resolveSessionId(inbound, binding) {
490
+ const explicitSessionId = autonomousSessionIdOverride(inbound.metadata);
491
+ if (explicitSessionId) {
492
+ return explicitSessionId;
493
+ }
414
494
  const key = conversationKey(inbound, binding);
415
495
  const existing = this.#sessionByConversation.get(key);
416
496
  if (existing) {
@@ -717,10 +797,24 @@ export class PiMessagingOperatorBackend {
717
797
  }
718
798
  this.#activePromptCountsBySession.set(sessionId, current - 1);
719
799
  }
720
- #sessionPersistence(repoRoot, sessionId) {
800
+ #sessionPersistence(repoRoot, sessionId, overrides) {
721
801
  if (!this.#persistSessions) {
722
802
  return undefined;
723
803
  }
804
+ if (overrides.sessionFile) {
805
+ return {
806
+ mode: "open",
807
+ sessionDir: overrides.sessionDir,
808
+ sessionFile: overrides.sessionFile,
809
+ };
810
+ }
811
+ if (overrides.sessionDir) {
812
+ return {
813
+ mode: "open",
814
+ sessionDir: overrides.sessionDir,
815
+ sessionFile: join(overrides.sessionDir, `${sessionFileStem(sessionId)}.jsonl`),
816
+ };
817
+ }
724
818
  const sessionDir = this.#sessionDirForRepoRoot(repoRoot);
725
819
  const sessionFile = join(sessionDir, `${sessionFileStem(sessionId)}.jsonl`);
726
820
  return {
@@ -729,15 +823,25 @@ export class PiMessagingOperatorBackend {
729
823
  sessionFile,
730
824
  };
731
825
  }
732
- async #createSession(repoRoot, sessionId, nowMs) {
826
+ async #createSession(repoRoot, sessionId, nowMs, overrides) {
827
+ const provider = overrides.provider ?? this.#provider;
828
+ const model = overrides.model ?? this.#model;
829
+ const thinking = overrides.thinking ?? this.#thinking;
830
+ const profileKey = operatorSessionProfileKey({
831
+ provider,
832
+ model,
833
+ thinking,
834
+ sessionFile: overrides.sessionFile,
835
+ sessionDir: overrides.sessionDir,
836
+ });
733
837
  const session = await this.#sessionFactory({
734
838
  cwd: repoRoot,
735
839
  systemPrompt: this.#systemPrompt,
736
- provider: this.#provider,
737
- model: this.#model,
738
- thinking: this.#thinking,
840
+ provider,
841
+ model,
842
+ thinking,
739
843
  extensionPaths: this.#extensionPaths,
740
- session: this.#sessionPersistence(repoRoot, sessionId),
844
+ session: this.#sessionPersistence(repoRoot, sessionId, overrides),
741
845
  bashToolOptions: {
742
846
  spawnHook: (context) => {
743
847
  const turnEnv = this.#autonomousTurnEnvBySession.get(sessionId);
@@ -770,20 +874,28 @@ export class PiMessagingOperatorBackend {
770
874
  repoRoot,
771
875
  createdAtMs: nowMs,
772
876
  lastUsedAtMs: nowMs,
877
+ profileKey,
773
878
  };
774
879
  }
775
- async #resolveSession(sessionId, repoRoot) {
880
+ async #resolveSession(sessionId, repoRoot, overrides) {
776
881
  const nowMs = Math.trunc(this.#nowMs());
777
882
  this.#pruneSessions(nowMs);
883
+ const requestedProfileKey = operatorSessionProfileKey({
884
+ provider: overrides.provider ?? this.#provider,
885
+ model: overrides.model ?? this.#model,
886
+ thinking: overrides.thinking ?? this.#thinking,
887
+ sessionFile: overrides.sessionFile,
888
+ sessionDir: overrides.sessionDir,
889
+ });
778
890
  const existing = this.#sessions.get(sessionId);
779
- if (existing && existing.repoRoot === repoRoot) {
891
+ if (existing && existing.repoRoot === repoRoot && existing.profileKey === requestedProfileKey) {
780
892
  existing.lastUsedAtMs = nowMs;
781
893
  return existing;
782
894
  }
783
- if (existing && existing.repoRoot !== repoRoot) {
895
+ if (existing) {
784
896
  this.#disposeSession(sessionId);
785
897
  }
786
- const created = await this.#createSession(repoRoot, sessionId, nowMs);
898
+ const created = await this.#createSession(repoRoot, sessionId, nowMs, overrides);
787
899
  this.#sessions.set(sessionId, created);
788
900
  this.#pruneSessions(nowMs);
789
901
  return created;
@@ -835,9 +947,12 @@ export class PiMessagingOperatorBackend {
835
947
  }
836
948
  }
837
949
  async runTurn(input) {
838
- const sessionRecord = await this.#resolveSession(input.sessionId, input.inbound.repo_root);
950
+ const overrides = autonomousOperatorSessionOverrides(input.inbound.metadata, input.inbound.repo_root);
951
+ const sessionRecord = await this.#resolveSession(input.sessionId, input.inbound.repo_root, overrides);
839
952
  const session = sessionRecord.session;
840
953
  let assistantText = "";
954
+ let assistantStopReason = null;
955
+ let assistantErrorMessage = null;
841
956
  let capturedCommand = null;
842
957
  let capturedUiDocs = [];
843
958
  const turnEnv = autonomousTurnEnvironment(input.inbound.metadata);
@@ -851,6 +966,8 @@ export class PiMessagingOperatorBackend {
851
966
  // Capture assistant text for fallback responses.
852
967
  if (event?.type === "message_end" && event?.message?.role === "assistant") {
853
968
  const msg = event.message;
969
+ assistantStopReason = typeof msg.stopReason === "string" ? msg.stopReason.trim().toLowerCase() : null;
970
+ assistantErrorMessage = typeof msg.errorMessage === "string" ? msg.errorMessage.trim() : null;
854
971
  if (typeof msg.text === "string") {
855
972
  assistantText = msg.text;
856
973
  }
@@ -917,6 +1034,8 @@ export class PiMessagingOperatorBackend {
917
1034
  }
918
1035
  await session.agent.waitForIdle();
919
1036
  assistantText = "";
1037
+ assistantStopReason = null;
1038
+ assistantErrorMessage = null;
920
1039
  capturedCommand = null;
921
1040
  await promptOnce();
922
1041
  }
@@ -925,7 +1044,7 @@ export class PiMessagingOperatorBackend {
925
1044
  await this.#auditTurn(input, {
926
1045
  outcome: "error",
927
1046
  reason: err instanceof Error ? err.message : "operator_backend_error",
928
- messagePreview: assistantText,
1047
+ messagePreview: assistantText || assistantErrorMessage || undefined,
929
1048
  });
930
1049
  throw err;
931
1050
  }
@@ -951,11 +1070,14 @@ export class PiMessagingOperatorBackend {
951
1070
  // Otherwise treat the assistant text as a plain response.
952
1071
  const message = assistantText.trim();
953
1072
  if (!message) {
1073
+ const providerFailureCode = classifyProviderFailureCodeFromMessage(assistantErrorMessage);
1074
+ const emptyResponseCode = providerFailureCode ?? (assistantStopReason === "aborted" ? "operator_cancelled" : null) ?? "operator_empty_response";
954
1075
  await this.#auditTurn(input, {
955
1076
  outcome: "error",
956
- reason: "operator_empty_response",
1077
+ reason: emptyResponseCode,
1078
+ messagePreview: assistantErrorMessage || undefined,
957
1079
  });
958
- throw new Error("operator_empty_response");
1080
+ throw new Error(emptyResponseCode);
959
1081
  }
960
1082
  const responseMessage = message.slice(0, OPERATOR_RESPONSE_MAX_CHARS);
961
1083
  await this.#auditTurn(input, {
package/package.json CHANGED
@@ -1,34 +1,34 @@
1
1
  {
2
- "name": "@femtomc/mu-agent",
3
- "version": "26.3.1",
4
- "description": "Shared operator runtime for mu assistant sessions and serve extensions.",
5
- "keywords": [
6
- "mu",
7
- "agent",
8
- "runtime",
9
- "chat",
10
- "extensions"
11
- ],
12
- "type": "module",
13
- "main": "./dist/index.js",
14
- "types": "./dist/index.d.ts",
15
- "exports": {
16
- ".": {
17
- "types": "./dist/index.d.ts",
18
- "default": "./dist/index.js"
19
- }
20
- },
21
- "files": [
22
- "dist/**",
23
- "prompts/**",
24
- "themes/**"
25
- ],
26
- "dependencies": {
27
- "@femtomc/mu-core": "26.3.1",
28
- "@mariozechner/pi-agent-core": "^0.54.2",
29
- "@mariozechner/pi-ai": "^0.54.2",
30
- "@mariozechner/pi-coding-agent": "^0.54.2",
31
- "@mariozechner/pi-tui": "^0.54.2",
32
- "zod": "^4.1.9"
33
- }
2
+ "name": "@femtomc/mu-agent",
3
+ "version": "26.3.3",
4
+ "description": "Shared operator runtime for mu assistant sessions and serve extensions.",
5
+ "keywords": [
6
+ "mu",
7
+ "agent",
8
+ "runtime",
9
+ "chat",
10
+ "extensions"
11
+ ],
12
+ "type": "module",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist/**",
23
+ "prompts/**",
24
+ "themes/**"
25
+ ],
26
+ "dependencies": {
27
+ "@femtomc/mu-core": "26.3.3",
28
+ "@mariozechner/pi-agent-core": "^0.54.2",
29
+ "@mariozechner/pi-ai": "^0.54.2",
30
+ "@mariozechner/pi-coding-agent": "^0.54.2",
31
+ "@mariozechner/pi-tui": "^0.54.2",
32
+ "zod": "^4.1.9"
33
+ }
34
34
  }