@astrosheep/keiyaku 4.5.16 → 4.5.17

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.
@@ -219,6 +219,34 @@ function turnOutcomeEmitter(launch, soul) {
219
219
  })();
220
220
  };
221
221
  }
222
+ function bodyEndEmitter(launch, soul) {
223
+ let plugins;
224
+ const reportDiagnostic = (message) => {
225
+ void recordPluginDiagnostic(launch.paths, "body end", message);
226
+ };
227
+ return (bodySequence, end, diagnostic) => {
228
+ void (async () => {
229
+ try {
230
+ plugins ??= pluginRuntime({
231
+ world: await World.at(worldRootForAkumaPaths(launch.paths)),
232
+ reportDiagnostic,
233
+ });
234
+ const runtime = await plugins;
235
+ await runtime.emit({
236
+ kind: "akuma.body-ended",
237
+ akumaId: soul.id,
238
+ bodySequence,
239
+ end,
240
+ ...(diagnostic === undefined ? {} : { diagnostic }),
241
+ ...(launch.completion?.contractId === undefined ? {} : { contractId: launch.completion.contractId }),
242
+ }, reportDiagnostic);
243
+ }
244
+ catch (error) {
245
+ await recordPluginDiagnostic(launch.paths, "body end", error);
246
+ }
247
+ })();
248
+ };
249
+ }
222
250
  async function runBodyTurns(input) {
223
251
  const { launch, soul, adapter, bodySequence, supervisor, runtime } = input;
224
252
  let initial = launch.initialBody;
@@ -393,10 +421,12 @@ export async function driveAkumaBody(launch, adapter, runtimeInput = {}) {
393
421
  let pendingTellDisposition = undefined;
394
422
  let bodySequence;
395
423
  let decidedDisposition = null;
424
+ let emitBodyEnd;
396
425
  try {
397
426
  const soul = await bornSoul(launch, leash, runtime.now());
398
427
  if (soul === null)
399
428
  return;
429
+ emitBodyEnd = bodyEndEmitter(launch, soul);
400
430
  if (launch.seed === undefined && launch.initialBody === undefined) {
401
431
  const [heart, requests] = await Promise.all([readHeart(launch.paths), readNonterminalRequests(launch.paths)]);
402
432
  if (heart.pending.length === 0 && requests.length === 0)
@@ -447,6 +477,12 @@ export async function driveAkumaBody(launch, adapter, runtimeInput = {}) {
447
477
  at: runtime.now(),
448
478
  handoff: pendingTellDisposition === "handoff",
449
479
  });
480
+ const finalBody = (await readHeart(launch.paths)).latestBody;
481
+ if (emitBodyEnd !== undefined &&
482
+ finalBody?.sequence === bodySequence &&
483
+ (finalBody.end !== undefined || finalBody.hung !== undefined)) {
484
+ emitBodyEnd(bodySequence, finalBody.hung === undefined ? finalBody.end : "hung", finalBody.hung?.diagnostic);
485
+ }
450
486
  }
451
487
  leash.release();
452
488
  if (decidedDisposition !== null) {
@@ -87,14 +87,21 @@ function optionAdmission(options) {
87
87
  };
88
88
  }
89
89
  function grokSessionMeta(config, options) {
90
- const configured = config === undefined ? {} : { freshSessionMeta: config, loadSessionMeta: config };
90
+ // Keiyaku does not implement Grok's reverse ask_user_question request, so
91
+ // keep that unsupported tool out of every session's advertised toolset.
92
+ const sessionMeta = { ...(config ?? {}), askUserQuestion: false };
93
+ const configured = { freshSessionMeta: sessionMeta, loadSessionMeta: sessionMeta };
91
94
  if (options.systemPrompt === undefined || options.systemPrompt.length === 0)
92
95
  return configured;
93
96
  if (options.systemPromptMode === "append")
94
- return { ...configured, freshSessionMeta: { ...config, rules: options.systemPrompt } };
97
+ return { ...configured, freshSessionMeta: { ...sessionMeta, rules: options.systemPrompt } };
95
98
  if (options.systemPromptMode === "replace") {
96
99
  const meta = { systemPromptOverride: options.systemPrompt };
97
- return { ...configured, freshSessionMeta: { ...config, ...meta }, loadSessionMeta: { ...config, ...meta } };
100
+ return {
101
+ ...configured,
102
+ freshSessionMeta: { ...sessionMeta, ...meta },
103
+ loadSessionMeta: { ...sessionMeta, ...meta },
104
+ };
98
105
  }
99
106
  return configured;
100
107
  }
@@ -137,10 +144,12 @@ export function createGrokBuildProvider(execution, dependencies = {}) {
137
144
  argv: argv(execution, input.options),
138
145
  ...(execution.env === undefined ? {} : { env: execution.env }),
139
146
  };
147
+ const sessionMeta = grokSessionMeta(execution.config, input.options);
140
148
  return withInterject(await startAcpSession(launch, input, {
141
149
  ...dependencies,
142
150
  interpretTool: interpretGrokTool,
143
- ...grokSessionMeta(execution.config, input.options),
151
+ freshSessionMeta: { ...(dependencies.freshSessionMeta ?? {}), ...(sessionMeta.freshSessionMeta ?? {}) },
152
+ loadSessionMeta: { ...(dependencies.loadSessionMeta ?? {}), ...(sessionMeta.loadSessionMeta ?? {}) },
144
153
  }, custody));
145
154
  };
146
155
  return {
@@ -2,5 +2,5 @@ export * from "./library/keiyaku.js";
2
2
  export { settings } from "./settings.js";
3
3
  export { World, WorldError } from "./world.js";
4
4
  export type { WorldResolution, WorldResolutionInput, WorldRoot } from "./world.js";
5
- export type { KeiyakuPlugin, PluginContext, PluginHooks, PluginInstance, PluginManifest, PluginOutcome, PluginSignal, PluginSignalMap, } from "./plugin/public.js";
5
+ export type { KeiyakuPlugin, PluginContext, PluginHooks, PluginInstance, PluginManifest, PluginBodyEnd, PluginOutcome, PluginSignal, PluginSignalMap, } from "./plugin/public.js";
6
6
  export type { Settings, SettingsEntry, SettingsInput, SettingsNamespaceFailure, SettingsNamespaceView, SettingsScope, SettingsScopeState, } from "./settings.js";
@@ -14,6 +14,7 @@ export type PluginOutcome = Readonly<{
14
14
  kind: "failed";
15
15
  reason: string;
16
16
  }>;
17
+ export type PluginBodyEnd = "exited" | "broke-off" | "put-down" | "hung";
17
18
  export type PluginSignalMap = Readonly<{
18
19
  "akuma.called": Readonly<{
19
20
  akumaId: string;
@@ -26,6 +27,13 @@ export type PluginSignalMap = Readonly<{
26
27
  outcome: PluginOutcome;
27
28
  contractId?: string;
28
29
  }>;
30
+ "akuma.body-ended": Readonly<{
31
+ akumaId: string;
32
+ bodySequence: number;
33
+ end: PluginBodyEnd;
34
+ diagnostic?: string;
35
+ contractId?: string;
36
+ }>;
29
37
  }>;
30
38
  export type PluginSignal = {
31
39
  [K in keyof PluginSignalMap]: Readonly<{
@@ -170,7 +170,7 @@ function handlers(pluginId, instance) {
170
170
  throw new TypeError("plugin signals must be an object");
171
171
  const registered = [];
172
172
  for (const [kind, handler] of Object.entries(instance.signals)) {
173
- if (kind !== "akuma.called" && kind !== "akuma.turn-outcome") {
173
+ if (kind !== "akuma.called" && kind !== "akuma.turn-outcome" && kind !== "akuma.body-ended") {
174
174
  throw new TypeError(`plugin signal is unknown: ${kind}`);
175
175
  }
176
176
  if (typeof handler !== "function")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrosheep/keiyaku",
3
- "version": "4.5.16",
3
+ "version": "4.5.17",
4
4
  "workspaces": [
5
5
  "plugins/*"
6
6
  ],