@ycodium-ai/agent-kimi 0.2.3254 → 0.2.3265

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/index.js +223 -42
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -93,7 +93,11 @@ var KIMI_CARD = {
93
93
  // src/kimiInstance.ts
94
94
  import * as NodeOS5 from "node:os";
95
95
  import * as NodePath7 from "node:path";
96
- import { mergeLaunchEnv, modelSelectionStringOption } from "@ycodium-ai/plugin-api/executor";
96
+ import {
97
+ mergeLaunchEnv,
98
+ modelSelectionStringOption,
99
+ raceAbort
100
+ } from "@ycodium-ai/plugin-api/executor";
97
101
  import { nodeStreamsFromHandle } from "@ycodium-ai/plugin-api/process-stdin";
98
102
 
99
103
  // ../../packages/ycodium-acp-executor/src/executor.ts
@@ -25126,11 +25130,15 @@ function createAcpConnection(options) {
25126
25130
  });
25127
25131
  };
25128
25132
  const close = (error62) => shutdown(error62 ?? new AcpConnectionClosedError());
25133
+ const abandonPending = (error62) => {
25134
+ rejectPending(error62);
25135
+ };
25129
25136
  return {
25130
25137
  request,
25131
25138
  begin,
25132
25139
  notify,
25133
25140
  awaitInboundIdle,
25141
+ abandonPending,
25134
25142
  close,
25135
25143
  closed
25136
25144
  };
@@ -25596,10 +25604,11 @@ function createExecutorPrompt({
25596
25604
  const prompt = async (input2) => {
25597
25605
  failIfPromptUnavailable();
25598
25606
  const started = requireStarted();
25607
+ let sessionId = started.sessionId;
25599
25608
  let record2;
25600
25609
  const settle2 = (rest) => settleTurn({
25601
25610
  expectedGeneration: started.generation,
25602
- expectedSessionId: started.sessionId,
25611
+ expectedSessionId: sessionId,
25603
25612
  record: record2,
25604
25613
  ...rest
25605
25614
  });
@@ -25683,12 +25692,32 @@ function createExecutorPrompt({
25683
25692
  const queuedTurnId = turnId;
25684
25693
  const isStale = () => interruptedTurnIds.has(queuedTurnId) || input2.expectedActiveTurnId !== void 0 && shared.activeTurnId !== queuedTurnId;
25685
25694
  if (!isStale()) {
25686
- shared.modelSelectionState = await applyRequestedModel({
25687
- state: shared.modelSelectionState,
25688
- acpSessionId: started.sessionId,
25689
- requestedModelId: input2.requestedModelId,
25690
- expectedGeneration: started.generation
25691
- });
25695
+ try {
25696
+ const applied = await applyRequestedModel({
25697
+ state: shared.modelSelectionState,
25698
+ acpSessionId: sessionId,
25699
+ setup: shared.startResult?.sessionSetupResult ?? {},
25700
+ requestedModelId: input2.requestedModelId,
25701
+ expectedGeneration: started.generation
25702
+ });
25703
+ shared.modelSelectionState = applied.state;
25704
+ sessionId = applied.sessionId;
25705
+ record2.sessionId = applied.sessionId;
25706
+ } catch (error62) {
25707
+ const failureCategory = readAcpFailureCategory(error62);
25708
+ if (failureCategory === "model-unavailable") {
25709
+ const errorMessage = error62 instanceof Error && error62.message.trim().length > 0 ? error62.message : "Requested model is not in this agent's catalog. This turn was not sent.";
25710
+ settle2({
25711
+ turnId,
25712
+ stopReason: "error",
25713
+ state: "failed",
25714
+ errorMessage,
25715
+ failureCategory
25716
+ });
25717
+ throw error62 instanceof Error ? withFailureCategory(error62, failureCategory) : error62;
25718
+ }
25719
+ throw error62;
25720
+ }
25692
25721
  }
25693
25722
  failIfDisposed();
25694
25723
  if (isStale()) {
@@ -25699,7 +25728,7 @@ function createExecutorPrompt({
25699
25728
  let written = false;
25700
25729
  try {
25701
25730
  response = await sendPromptRpc(
25702
- started.sessionId,
25731
+ sessionId,
25703
25732
  promptParts,
25704
25733
  () => {
25705
25734
  written = true;
@@ -25749,7 +25778,7 @@ function createExecutorPrompt({
25749
25778
  if (hooks.readContextWindow !== void 0) {
25750
25779
  try {
25751
25780
  contextWindow = await hooks.readContextWindow({
25752
- sessionId: started.sessionId,
25781
+ sessionId,
25753
25782
  promptResponse: response
25754
25783
  }) ?? void 0;
25755
25784
  } catch {
@@ -26392,6 +26421,56 @@ function acpInitializePayload(clientInfo, overrides) {
26392
26421
  };
26393
26422
  }
26394
26423
 
26424
+ // ../../packages/ycodium-acp-executor/src/refreshDeadline.ts
26425
+ var MODEL_CATALOG_REFRESH_TIMEOUT_MS = 9e4;
26426
+
26427
+ // ../../packages/ycodium-acp-executor/src/model-send.ts
26428
+ function judgeRequestedModel(input2) {
26429
+ const requested = normalizeModelId(input2.requestedModelId);
26430
+ const current = input2.state.currentModelId;
26431
+ if (requested === void 0 || requested === current) return { kind: "keep" };
26432
+ const hasCatalog = input2.state.advertisedModelValues.length > 0;
26433
+ const hasCurrent = current !== void 0;
26434
+ if (!hasCatalog && !hasCurrent) return { kind: "keep" };
26435
+ const canSwitch = input2.state.strategy === "session/set_model" && input2.state.sessionModelsAdvertised || input2.state.strategy === "config-option" && input2.state.modelConfigId !== void 0;
26436
+ const value = hasCatalog ? matchAdvertisedModelValue(requested, input2.state.advertisedModelValues) : void 0;
26437
+ if (value !== void 0 && value === current) return { kind: "keep" };
26438
+ if (value !== void 0 && canSwitch) return { kind: "switch", value };
26439
+ return input2.refreshed ? { kind: "unavailable" } : { kind: "refresh" };
26440
+ }
26441
+ function modelUnavailableError(requestedModelId, currentModelId) {
26442
+ const current = currentModelId ?? "its own model";
26443
+ return withFailureCategory(
26444
+ new Error(
26445
+ `Requested model "${requestedModelId}" is not in this agent's catalog; it is on "${current}". This turn was not sent. Refresh the model list in this agent's settings and try again.`
26446
+ ),
26447
+ "model-unavailable"
26448
+ );
26449
+ }
26450
+ var ModelCatalogRefreshTimeoutError = class extends Error {
26451
+ constructor() {
26452
+ super("model catalog refresh timed out");
26453
+ this.name = "ModelCatalogRefreshTimeoutError";
26454
+ }
26455
+ };
26456
+ function modelRefreshTimedOutError(requestedModelId) {
26457
+ return withFailureCategory(
26458
+ new Error(
26459
+ `Refreshing this agent's model list timed out, so this turn was not sent. Requested model "${requestedModelId}".`
26460
+ ),
26461
+ "model-unavailable"
26462
+ );
26463
+ }
26464
+ function modelRefreshFailedError(requestedModelId, error62) {
26465
+ const detail = error62 instanceof Error && error62.message.trim().length > 0 ? error62.message : "the model list could not be read";
26466
+ return withFailureCategory(
26467
+ new Error(
26468
+ `Refreshing this agent's model list failed (${detail}), so this turn was not sent. Requested model "${requestedModelId}".`
26469
+ ),
26470
+ "model-unavailable"
26471
+ );
26472
+ }
26473
+
26395
26474
  // ../../packages/ycodium-acp-executor/src/runtime-mode.ts
26396
26475
  function isRecord5(value) {
26397
26476
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -26440,43 +26519,131 @@ function createExecutorSession({
26440
26519
  failIfDisposed,
26441
26520
  shared
26442
26521
  }) {
26443
- const applyRequestedModel = async (input2) => {
26444
- const requestedModelId = normalizeModelId(input2.requestedModelId);
26445
- if (requestedModelId === void 0 || requestedModelId === input2.state.currentModelId || input2.state.strategy === "session/set_model" && !input2.state.sessionModelsAdvertised || input2.state.strategy === "config-option" && input2.state.modelConfigId === void 0) {
26446
- return input2.state;
26447
- }
26448
- const value = matchAdvertisedModelValue(requestedModelId, input2.state.advertisedModelValues);
26449
- if (value === void 0) {
26450
- if (requestedModelId !== shared.lastUnmatchedModelId) {
26451
- shared.lastUnmatchedModelId = requestedModelId;
26452
- options.log?.info("requested model is not in the agent catalog; keeping its own model", {
26453
- requestedModelId,
26454
- currentModelId: input2.state.currentModelId,
26455
- advertisedModelValues: input2.state.advertisedModelValues
26456
- });
26457
- }
26458
- return input2.state;
26522
+ const openFreshSession = async (expectedGeneration) => {
26523
+ const initialized = shared.initializeResult;
26524
+ if (initialized === void 0) {
26525
+ throw new Error("no handshake");
26526
+ }
26527
+ const mcpServers = filterMcpServersByAgentCapabilities(
26528
+ options.mcpServers ?? [],
26529
+ initialized.agentCapabilities
26530
+ );
26531
+ const additionalDirectories = options.additionalDirectories !== void 0 && options.additionalDirectories.length > 0 ? { additionalDirectories: options.additionalDirectories } : {};
26532
+ const created = await connection.request("session/new", {
26533
+ cwd: options.cwd,
26534
+ mcpServers,
26535
+ ...additionalDirectories
26536
+ });
26537
+ if (!isLive(expectedGeneration)) {
26538
+ throw new AcpExecutorDisposedError();
26459
26539
  }
26460
- if (value === input2.state.currentModelId) {
26461
- return input2.state;
26540
+ if (created.sessionId === void 0 || created.sessionId.length === 0) {
26541
+ throw new Error("session/new did not return a session id");
26462
26542
  }
26543
+ return { sessionId: created.sessionId, setup: created };
26544
+ };
26545
+ const switchModel = async (input2) => {
26463
26546
  let configOptions = input2.state.configOptions;
26464
26547
  if (input2.state.strategy === "config-option") {
26465
26548
  const switched = await connection.request(
26466
26549
  "session/set_config_option",
26467
- { sessionId: input2.acpSessionId, configId: input2.state.modelConfigId, value }
26550
+ { sessionId: input2.sessionId, configId: input2.state.modelConfigId, value: input2.value }
26468
26551
  );
26469
26552
  configOptions = switched?.configOptions ?? configOptions;
26470
26553
  } else {
26471
26554
  await connection.request("session/set_model", {
26472
- sessionId: input2.acpSessionId,
26473
- modelId: value
26555
+ sessionId: input2.sessionId,
26556
+ modelId: input2.value
26474
26557
  });
26475
26558
  }
26476
26559
  if (!isLive(input2.expectedGeneration)) {
26477
26560
  throw new AcpExecutorDisposedError();
26478
26561
  }
26479
- return { ...input2.state, currentModelId: value, configOptions };
26562
+ return { ...input2.state, currentModelId: input2.value, configOptions };
26563
+ };
26564
+ const adoptReopenedSession = (applied) => {
26565
+ if (shared.sessionId === void 0 && shared.startResult === void 0) return;
26566
+ const setup = applied.setup;
26567
+ shared.sessionId = applied.sessionId;
26568
+ shared.modelSelectionState = applied.state;
26569
+ shared.modeState = parseSessionModeState(setup);
26570
+ if (shared.startResult !== void 0) {
26571
+ shared.startResult = {
26572
+ ...shared.startResult,
26573
+ sessionId: applied.sessionId,
26574
+ sessionSetupResult: setup,
26575
+ modelConfigId: extractModelConfigId(setup),
26576
+ modelId: applied.state.currentModelId
26577
+ };
26578
+ }
26579
+ };
26580
+ const applyRequestedModel = async (input2) => {
26581
+ async function applyOnce(state, sessionId, setup, refreshed) {
26582
+ const requestedModelId = normalizeModelId(input2.requestedModelId) ?? "";
26583
+ const judgment = judgeRequestedModel({
26584
+ state,
26585
+ requestedModelId: input2.requestedModelId,
26586
+ refreshed
26587
+ });
26588
+ if (judgment.kind === "keep") return { state, sessionId, setup };
26589
+ if (judgment.kind === "unavailable") {
26590
+ throw modelUnavailableError(requestedModelId, state.currentModelId);
26591
+ }
26592
+ if (judgment.kind === "switch") {
26593
+ return {
26594
+ state: await switchModel({
26595
+ state,
26596
+ sessionId,
26597
+ value: judgment.value,
26598
+ expectedGeneration: input2.expectedGeneration
26599
+ }),
26600
+ sessionId,
26601
+ setup
26602
+ };
26603
+ }
26604
+ return refreshAndRejudge(requestedModelId);
26605
+ }
26606
+ async function refreshAndRejudge(requestedModelId) {
26607
+ const timeoutMs = options.modelCatalogRefreshTimeoutMs ?? MODEL_CATALOG_REFRESH_TIMEOUT_MS;
26608
+ let timedOut = false;
26609
+ const timeoutError = new ModelCatalogRefreshTimeoutError();
26610
+ let timer;
26611
+ const work = (async () => {
26612
+ await options.refreshCatalogForSend?.();
26613
+ if (timedOut) throw timeoutError;
26614
+ const reopened = await openFreshSession(input2.expectedGeneration);
26615
+ if (timedOut) throw timeoutError;
26616
+ const next = modelSelectionStateFromSetup(reopened.setup);
26617
+ const applied = await applyOnce(next, reopened.sessionId, reopened.setup, true);
26618
+ if (timedOut) throw timeoutError;
26619
+ adoptReopenedSession(applied);
26620
+ return applied;
26621
+ })();
26622
+ void work.then(
26623
+ () => void 0,
26624
+ () => void 0
26625
+ );
26626
+ const deadline = new Promise((_resolve, reject) => {
26627
+ timer = setTimeout(() => {
26628
+ timedOut = true;
26629
+ connection.abandonPending(timeoutError);
26630
+ reject(timeoutError);
26631
+ }, timeoutMs);
26632
+ });
26633
+ try {
26634
+ return await Promise.race([work, deadline]);
26635
+ } catch (error62) {
26636
+ if (error62 instanceof AcpExecutorDisposedError) throw error62;
26637
+ if (timedOut || error62 instanceof ModelCatalogRefreshTimeoutError) {
26638
+ throw modelRefreshTimedOutError(requestedModelId);
26639
+ }
26640
+ if (readAcpFailureCategory(error62) === "model-unavailable") throw error62;
26641
+ throw modelRefreshFailedError(requestedModelId, error62);
26642
+ } finally {
26643
+ if (timer !== void 0) clearTimeout(timer);
26644
+ }
26645
+ }
26646
+ return applyOnce(input2.state, input2.acpSessionId, input2.setup, false);
26480
26647
  };
26481
26648
  const startOnce = async (expectedGeneration) => {
26482
26649
  const initializePayload = acpInitializePayload(options.clientInfo, options.clientCapabilities);
@@ -26545,12 +26712,17 @@ function createExecutorSession({
26545
26712
  categories: unhandledCategories
26546
26713
  });
26547
26714
  }
26548
- const nextModelSelectionState = await applyRequestedModel({
26549
- state: modelSelectionStateFromSetup(setup),
26715
+ const openedSetup = setup;
26716
+ const appliedModel = await applyRequestedModel({
26717
+ state: modelSelectionStateFromSetup(openedSetup),
26550
26718
  acpSessionId: nextSessionId,
26719
+ setup: openedSetup,
26551
26720
  requestedModelId: options.requestedModelId,
26552
26721
  expectedGeneration
26553
26722
  });
26723
+ nextSessionId = appliedModel.sessionId;
26724
+ setup = appliedModel.setup;
26725
+ const nextModelSelectionState = appliedModel.state;
26554
26726
  await applyRequestedEffort({
26555
26727
  connection,
26556
26728
  log: options.log,
@@ -27085,7 +27257,6 @@ function createAcpExecutor(options) {
27085
27257
  currentModelId: void 0,
27086
27258
  advertisedModelValues: []
27087
27259
  },
27088
- lastUnmatchedModelId: void 0,
27089
27260
  initializeResult: void 0,
27090
27261
  startResult: void 0,
27091
27262
  startInFlight: void 0,
@@ -28220,6 +28391,7 @@ var createKimiTokenReader = (input2) => {
28220
28391
  // src/kimiModels.ts
28221
28392
  import {
28222
28393
  describeExecutorSpawnFailure,
28394
+ ExecutorSpawnAbortedError,
28223
28395
  ExecutorSpawnRefusedError,
28224
28396
  REASONING_OPTION_LABEL,
28225
28397
  reasoningEffortShortLabel
@@ -28300,10 +28472,13 @@ async function probeKimiModels(input2) {
28300
28472
  args: KIMI_MODEL_LIST_ARGS,
28301
28473
  cwd: process.cwd(),
28302
28474
  owner: { bindingId: host.bindingId },
28303
- ...Object.keys(env).length > 0 ? { env } : {}
28475
+ ...Object.keys(env).length > 0 ? { env } : {},
28476
+ ...input2.signal === void 0 ? {} : { signal: input2.signal }
28304
28477
  });
28305
28478
  } catch (error62) {
28306
- if (error62 instanceof ExecutorSpawnRefusedError) throw error62;
28479
+ if (error62 instanceof ExecutorSpawnRefusedError || error62 instanceof ExecutorSpawnAbortedError) {
28480
+ throw error62;
28481
+ }
28307
28482
  return { kind: "not-started", ...describeExecutorSpawnFailure(error62) };
28308
28483
  }
28309
28484
  try {
@@ -28329,14 +28504,15 @@ async function probeKimiModels(input2) {
28329
28504
  }
28330
28505
  }
28331
28506
  async function probeKimiVersion(input2) {
28332
- const { recipe, host, env } = input2;
28507
+ const { recipe, host, env, signal } = input2;
28333
28508
  return probeCliVersion({
28334
28509
  spawn: () => host.process.spawn({
28335
28510
  program: recipe.binaryPath,
28336
28511
  args: ["--version"],
28337
28512
  cwd: process.cwd(),
28338
28513
  owner: { bindingId: host.bindingId },
28339
- ...Object.keys(env).length > 0 ? { env } : {}
28514
+ ...Object.keys(env).length > 0 ? { env } : {},
28515
+ ...signal === void 0 ? {} : { signal }
28340
28516
  }),
28341
28517
  timeoutMs: PROBE_TIMEOUT_MS
28342
28518
  });
@@ -28522,7 +28698,7 @@ var createKimiInstance = (config2, host) => {
28522
28698
  events.close();
28523
28699
  });
28524
28700
  const instance = {
28525
- probe: async () => {
28701
+ probe: async (signal) => {
28526
28702
  if (recipe.binaryPath.length === 0) {
28527
28703
  return {
28528
28704
  installed: false,
@@ -28532,8 +28708,12 @@ var createKimiInstance = (config2, host) => {
28532
28708
  detail: "Kimi Code program path is not configured"
28533
28709
  };
28534
28710
  }
28711
+ if (signal?.aborted) throw new Error("aborted");
28535
28712
  const env = buildSpawnEnv(recipe, recipe.homePath);
28536
- const outcome = await probeKimi({ recipe, host, env });
28713
+ const outcome = await raceAbort(
28714
+ probeKimi({ recipe, host, env, ...signal === void 0 ? {} : { signal } }),
28715
+ signal
28716
+ );
28537
28717
  const auth = () => {
28538
28718
  switch (readKimiAuthState(resolveHomePath(recipe))) {
28539
28719
  case "signed-in":
@@ -28583,6 +28763,7 @@ var createKimiInstance = (config2, host) => {
28583
28763
  };
28584
28764
  }
28585
28765
  },
28766
+ readCliVersion: () => recipe.binaryPath.length === 0 ? Promise.resolve(null) : probeKimiVersion({ recipe, host, env: buildSpawnEnv(recipe, recipe.homePath) }),
28586
28767
  // 暂不处理 input.readOnlyDirectories(有意为之):kimi 经共享的 ycodium-acp-executor 起会话,
28587
28768
  // 还没用真机确认这家 CLI 对 cwd 之外的读怎么处理、要不要放行。确认之后再接这一栏。
28588
28769
  startSession: async (input2, signal) => {
@@ -28824,7 +29005,7 @@ var executors = [
28824
29005
  ];
28825
29006
  var index_default = definePlugin({
28826
29007
  id: "agent-kimi",
28827
- apiVersion: 30,
29008
+ apiVersion: 31,
28828
29009
  executors,
28829
29010
  activate(ctx) {
28830
29011
  ctx.log.info("Kimi Code executor ready");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-kimi",
3
- "version": "0.2.3254",
3
+ "version": "0.2.3265",
4
4
  "description": "Kimi Code executor: runs `kimi acp` over Agent Client Protocol stdio.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -21,9 +21,9 @@
21
21
  "@types/node": "24.12.4",
22
22
  "esbuild": "0.28.1",
23
23
  "vite-plus": "0.2.2",
24
- "ycodium-executor-testing": "0.0.0",
25
- "ycodium-acp-executor": "0.2.3254",
26
- "@ycodium-ai/plugin-api": "0.2.3254"
24
+ "@ycodium-ai/plugin-api": "0.2.3265",
25
+ "ycodium-acp-executor": "0.2.3265",
26
+ "ycodium-executor-testing": "0.0.0"
27
27
  },
28
28
  "ycodium": {
29
29
  "plugin": "./dist/index.js",