@astrosheep/keiyaku 4.6.19 → 4.6.20

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 (102) hide show
  1. package/README.md +7 -3
  2. package/build/plugins/pi/README.md +111 -0
  3. package/build/plugins/pi/akuma-tools.ts +310 -0
  4. package/build/plugins/pi/keiyaku.ts +2 -0
  5. package/build/src/akuma/akuma-call.d.ts +4 -1
  6. package/build/src/akuma/akuma-call.js +24 -7
  7. package/build/src/akuma/akuma-instance.d.ts +28 -8
  8. package/build/src/akuma/akuma-instance.js +85 -42
  9. package/build/src/akuma/akuma-owner.d.ts +18 -9
  10. package/build/src/akuma/akuma-owner.js +31 -25
  11. package/build/src/akuma/akuma-selection-execution.d.ts +4 -1
  12. package/build/src/akuma/akuma-selection-execution.js +8 -4
  13. package/build/src/akuma/akuma.d.ts +17 -0
  14. package/build/src/akuma/body-launch.d.ts +107 -0
  15. package/build/src/akuma/body-launch.js +57 -0
  16. package/build/src/akuma/body-supervisor.d.ts +7 -6
  17. package/build/src/akuma/body-supervisor.js +17 -12
  18. package/build/src/akuma/body.d.ts +13 -94
  19. package/build/src/akuma/body.js +124 -296
  20. package/build/src/akuma/call-input.d.ts +2 -0
  21. package/build/src/akuma/call-input.js +21 -1
  22. package/build/src/akuma/call-request.d.ts +6 -2
  23. package/build/src/akuma/call-request.js +9 -1
  24. package/build/src/akuma/detached-body.d.ts +9 -0
  25. package/build/src/akuma/detached-body.js +94 -0
  26. package/build/src/akuma/execution-instructions.d.ts +8 -0
  27. package/build/src/akuma/execution-instructions.js +17 -0
  28. package/build/src/akuma/heart/facts.d.ts +21 -1
  29. package/build/src/akuma/heart/facts.js +10 -0
  30. package/build/src/akuma/heart/index.d.ts +16 -1
  31. package/build/src/akuma/heart/index.js +95 -30
  32. package/build/src/akuma/heart/rows.d.ts +14 -2
  33. package/build/src/akuma/heart/rows.js +48 -4
  34. package/build/src/akuma/heart/schema.d.ts +4 -1
  35. package/build/src/akuma/heart/schema.js +87 -30
  36. package/build/src/akuma/heart/soul.js +4 -0
  37. package/build/src/akuma/heart/storage.d.ts +1 -0
  38. package/build/src/akuma/heart/storage.js +59 -15
  39. package/build/src/akuma/heart/timeline.d.ts +6 -4
  40. package/build/src/akuma/heart/timeline.js +14 -4
  41. package/build/src/akuma/in-process-body.d.ts +5 -0
  42. package/build/src/akuma/in-process-body.js +57 -0
  43. package/build/src/akuma/index.d.ts +1 -1
  44. package/build/src/akuma/projection.d.ts +44 -1
  45. package/build/src/akuma/projection.js +13 -1
  46. package/build/src/akuma/provider.d.ts +4 -0
  47. package/build/src/akuma/providers/acp/core.js +1 -1
  48. package/build/src/akuma/providers/acp/index.js +3 -0
  49. package/build/src/akuma/providers/claude/index.js +8 -5
  50. package/build/src/akuma/providers/codex-app-server/configuration.d.ts +5 -0
  51. package/build/src/akuma/providers/codex-app-server/configuration.js +72 -0
  52. package/build/src/akuma/providers/codex-app-server/index.js +7 -10
  53. package/build/src/akuma/providers/execution-environment.d.ts +8 -2
  54. package/build/src/akuma/providers/execution-environment.js +10 -1
  55. package/build/src/akuma/providers/grok-build/index.js +23 -16
  56. package/build/src/akuma/providers/index.d.ts +1 -0
  57. package/build/src/akuma/providers/index.js +8 -0
  58. package/build/src/akuma/providers/opencode-sdk/index.js +9 -0
  59. package/build/src/akuma/providers/opencode-sdk/session.d.ts +6 -0
  60. package/build/src/akuma/providers/opencode-sdk/session.js +4 -3
  61. package/build/src/akuma/providers/paseo/index.js +8 -2
  62. package/build/src/akuma/providers/pi/index.js +27 -10
  63. package/build/src/akuma/publication.d.ts +4 -3
  64. package/build/src/akuma/publication.js +21 -18
  65. package/build/src/akuma/selection-observation.d.ts +51 -0
  66. package/build/src/akuma/selection-owner-port.d.ts +2 -1
  67. package/build/src/akuma/selection-owner-port.js +4 -3
  68. package/build/src/akuma/turn-drive.d.ts +4 -2
  69. package/build/src/akuma/turn-drive.js +58 -21
  70. package/build/src/akuma-body.d.ts +0 -10
  71. package/build/src/akuma-body.js +13 -118
  72. package/build/src/body-host.d.ts +28 -0
  73. package/build/src/body-host.js +86 -0
  74. package/build/src/body-requests.d.ts +13 -0
  75. package/build/src/body-requests.js +131 -0
  76. package/build/src/cli/commands/akuma-grammar.d.ts +8 -1
  77. package/build/src/cli/commands/akuma-grammar.js +36 -6
  78. package/build/src/cli/commands/akuma.js +11 -0
  79. package/build/src/cli/commands/report.d.ts +6 -0
  80. package/build/src/cli/commands/report.js +31 -0
  81. package/build/src/cli/parse.js +1 -0
  82. package/build/src/cli/render/akuma-activity.js +27 -17
  83. package/build/src/cli/render/terminal.d.ts +5 -0
  84. package/build/src/cli/render/terminal.js +7 -0
  85. package/build/src/cli/runtime.js +4 -1
  86. package/build/src/index.d.ts +3 -1
  87. package/build/src/index.js +1 -0
  88. package/build/src/library/akuma-creation.d.ts +7 -3
  89. package/build/src/library/akuma-creation.js +23 -11
  90. package/build/src/library/akumas.d.ts +4 -1
  91. package/build/src/library/akumas.js +13 -5
  92. package/build/src/library/selection.d.ts +2 -1
  93. package/build/src/library/selection.js +6 -3
  94. package/build/src/plugin/public.d.ts +11 -0
  95. package/build/src/plugin/runtime.js +1 -0
  96. package/build/src/runtime/proc/windows-launch.exe +0 -0
  97. package/package.json +2 -2
  98. package/plugins/paseo/plugin/server/keiyaku.ts +1 -0
  99. package/plugins/paseo/plugin/server/mirror.ts +2 -2
  100. package/plugins/pi/README.md +111 -0
  101. package/plugins/pi/akuma-tools.ts +310 -0
  102. package/plugins/pi/keiyaku.ts +2 -0
@@ -15,6 +15,14 @@ declare const callRowSchema: z.ZodObject<{
15
15
  at: z.ZodString;
16
16
  text: z.ZodString;
17
17
  }, z.core.$strict>;
18
+ declare const reportRowSchema: z.ZodObject<{
19
+ kind: z.ZodLiteral<"report">;
20
+ sequence: z.ZodNumber;
21
+ bodySequence: z.ZodNumber;
22
+ turnSequence: z.ZodNumber;
23
+ text: z.ZodString;
24
+ at: z.ZodString;
25
+ }, z.core.$strict>;
18
26
  declare const textRowSchema: (kind: "said" | "thought" | "note") => z.ZodObject<{
19
27
  kind: z.ZodLiteral<"note" | "thought" | "said">;
20
28
  sequence: z.ZodNumber;
@@ -70,6 +78,9 @@ declare const outcomeRowSchema: z.ZodObject<{
70
78
  kind: z.ZodLiteral<"failed">;
71
79
  historyId: z.ZodString;
72
80
  diagnostic: z.ZodString;
81
+ }, z.core.$strict>, z.ZodObject<{
82
+ kind: z.ZodLiteral<"canceled">;
83
+ historyId: z.ZodString;
73
84
  }, z.core.$strict>]>;
74
85
  }, z.core.$strict>;
75
86
  declare const activeToolRowSchema: z.ZodObject<{
@@ -238,6 +249,13 @@ declare const unsettledToolRowSchema: z.ZodObject<{
238
249
  truncated: z.ZodOptional<z.ZodLiteral<true>>;
239
250
  }, z.core.$strict>;
240
251
  declare const openSnapshotRowSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodObject<{
252
+ kind: z.ZodLiteral<"report">;
253
+ sequence: z.ZodNumber;
254
+ bodySequence: z.ZodNumber;
255
+ turnSequence: z.ZodNumber;
256
+ text: z.ZodString;
257
+ at: z.ZodString;
258
+ }, z.core.$strict>, z.ZodObject<{
241
259
  kind: z.ZodLiteral<"call">;
242
260
  sequence: z.ZodNumber;
243
261
  turnSequence: z.ZodNumber;
@@ -409,6 +427,13 @@ declare const openSnapshotRowSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z
409
427
  truncated: z.ZodOptional<z.ZodLiteral<true>>;
410
428
  }, z.core.$strict>]>;
411
429
  declare const idleSnapshotRowSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodObject<{
430
+ kind: z.ZodLiteral<"report">;
431
+ sequence: z.ZodNumber;
432
+ bodySequence: z.ZodNumber;
433
+ turnSequence: z.ZodNumber;
434
+ text: z.ZodString;
435
+ at: z.ZodString;
436
+ }, z.core.$strict>, z.ZodObject<{
412
437
  kind: z.ZodLiteral<"call">;
413
438
  sequence: z.ZodNumber;
414
439
  turnSequence: z.ZodNumber;
@@ -601,6 +626,13 @@ export declare const activitySnapshotSchema: z.ZodUnion<readonly [z.ZodObject<{
601
626
  }, z.core.$strict>, z.ZodObject<{
602
627
  kind: z.ZodLiteral<"row">;
603
628
  row: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodObject<{
629
+ kind: z.ZodLiteral<"report">;
630
+ sequence: z.ZodNumber;
631
+ bodySequence: z.ZodNumber;
632
+ turnSequence: z.ZodNumber;
633
+ text: z.ZodString;
634
+ at: z.ZodString;
635
+ }, z.core.$strict>, z.ZodObject<{
604
636
  kind: z.ZodLiteral<"call">;
605
637
  sequence: z.ZodNumber;
606
638
  turnSequence: z.ZodNumber;
@@ -806,6 +838,9 @@ export declare const activitySnapshotSchema: z.ZodUnion<readonly [z.ZodObject<{
806
838
  kind: z.ZodLiteral<"failed">;
807
839
  historyId: z.ZodString;
808
840
  diagnostic: z.ZodString;
841
+ }, z.core.$strict>, z.ZodObject<{
842
+ kind: z.ZodLiteral<"canceled">;
843
+ historyId: z.ZodString;
809
844
  }, z.core.$strict>]>;
810
845
  }, z.core.$strict>>;
811
846
  entries: z.ZodReadonly<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
@@ -814,6 +849,13 @@ export declare const activitySnapshotSchema: z.ZodUnion<readonly [z.ZodObject<{
814
849
  }, z.core.$strict>, z.ZodObject<{
815
850
  kind: z.ZodLiteral<"row">;
816
851
  row: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodObject<{
852
+ kind: z.ZodLiteral<"report">;
853
+ sequence: z.ZodNumber;
854
+ bodySequence: z.ZodNumber;
855
+ turnSequence: z.ZodNumber;
856
+ text: z.ZodString;
857
+ at: z.ZodString;
858
+ }, z.core.$strict>, z.ZodObject<{
817
859
  kind: z.ZodLiteral<"call">;
818
860
  sequence: z.ZodNumber;
819
861
  turnSequence: z.ZodNumber;
@@ -941,7 +983,8 @@ type CallRow = z.infer<typeof callRowSchema>;
941
983
  type SaidRow = z.infer<ReturnType<typeof textRowSchema>>;
942
984
  type ThoughtRow = z.infer<ReturnType<typeof textRowSchema>>;
943
985
  type NoteRow = z.infer<ReturnType<typeof textRowSchema>>;
944
- type TurnNarrationRow = CallRow | SaidRow | ThoughtRow | NoteRow;
986
+ export type ReportRow = z.infer<typeof reportRowSchema>;
987
+ type TurnNarrationRow = CallRow | SaidRow | ThoughtRow | NoteRow | ReportRow;
945
988
  export type { TellRow } from "./heart/facts.js";
946
989
  export type OutcomeRow = z.infer<typeof outcomeRowSchema>;
947
990
  export type ActiveToolRow = z.infer<typeof activeToolRowSchema>;
@@ -1,5 +1,5 @@
1
1
  import { toolCallSchema, toolResultSchema, toolInputSchema, fileChangeSchema, diffstatSchema, } from "./heart/activity-schema.js";
2
- import { projectTell } from "./heart/facts.js";
2
+ import { projectTell, reportFactSchema } from "./heart/facts.js";
3
3
  import { z } from "zod";
4
4
  const nonblankTextSchema = z.string().refine((value) => value.trim() !== "");
5
5
  const countSchema = z.number().int().nonnegative();
@@ -47,6 +47,7 @@ const callRowSchema = z
47
47
  text: z.string(),
48
48
  })
49
49
  .strict();
50
+ const reportRowSchema = reportFactSchema;
50
51
  const textRowSchema = (kind) => z
51
52
  .object({
52
53
  kind: z.literal(kind),
@@ -78,6 +79,7 @@ const outcomeSchema = z.union([
78
79
  })
79
80
  .strict(),
80
81
  z.object({ kind: z.literal("failed"), historyId: nonblankTextSchema, diagnostic: z.string() }).strict(),
82
+ z.object({ kind: z.literal("canceled"), historyId: nonblankTextSchema }).strict(),
81
83
  ]);
82
84
  const outcomeRowSchema = z
83
85
  .object({
@@ -129,6 +131,7 @@ const unsettledToolRowSchema = z
129
131
  })
130
132
  .strict();
131
133
  const snapshotFactRowSchema = z.union([
134
+ reportRowSchema,
132
135
  callRowSchema,
133
136
  textRowSchema("said"),
134
137
  textRowSchema("thought"),
@@ -200,6 +203,8 @@ function publicOutcome(turnSequence, outcome) {
200
203
  const historyId = `turn/${turnSequence}`;
201
204
  if (outcome.kind === "answered")
202
205
  return { kind: "answered", historyId, answer: outcome.answer };
206
+ if (outcome.kind === "canceled")
207
+ return { kind: "canceled", historyId };
203
208
  return { kind: "failed", historyId, diagnostic: outcome.diagnostic };
204
209
  }
205
210
  export function selectExactHistory(rows, id) {
@@ -409,6 +414,13 @@ export function projectTurns(facts, retained = {
409
414
  else
410
415
  turn.rows.push(row);
411
416
  }
417
+ else if (fact.kind === "report") {
418
+ const turn = state.turnsBySequence.get(fact.turnSequence);
419
+ if (turn === undefined)
420
+ state.orphanRows.push(fact);
421
+ else
422
+ turn.rows.push(fact);
423
+ }
412
424
  else if (fact.kind === "tell") {
413
425
  state.tells.push(projectTell(fact));
414
426
  }
@@ -1,4 +1,5 @@
1
1
  import { type ResumeCoordinate } from "./coordinate.js";
2
+ import type { ExecutionCoordinate } from "./providers/execution-environment.js";
2
3
  import type { ProviderOptions } from "./provider-recipe.js";
3
4
  export type { ResumeCoordinate } from "./coordinate.js";
4
5
  export { AKUMA_REQUESTS_ENV, AKUMA_REQUESTS_ENTRY_ENV } from "./providers/execution-environment.js";
@@ -130,7 +131,10 @@ export type DriveInput = Readonly<{
130
131
  }>[];
131
132
  cwd: string;
132
133
  options: ProviderOptions;
134
+ /** Fresh execution context, never part of the persisted personality recipe. */
135
+ runtimeInstructions?: string;
133
136
  signal: AbortSignal;
137
+ execution?: ExecutionCoordinate;
134
138
  requests: Readonly<{
135
139
  dir: string;
136
140
  entry?: string;
@@ -169,7 +169,7 @@ export async function startAcpSession(launch, input, dependencies = {}, custody)
169
169
  const child = (dependencies.spawnProcess ?? spawnStdioProcess)({
170
170
  argv: launch.argv,
171
171
  cwd: input.cwd,
172
- env: akumaExecutionEnvironment(globalThis.process.env, launch.env, input.requests?.dir),
172
+ env: akumaExecutionEnvironment(globalThis.process.env, launch.env, input.requests?.dir, [], input.execution),
173
173
  });
174
174
  let abortOwned = async () => await child.close(true);
175
175
  let forceDisposeOwned = async () => await child.close(true);
@@ -47,6 +47,9 @@ export function createAcpProvider(execution, dependencies = {}) {
47
47
  throw new TypeError("ACP provider execution requires executable");
48
48
  const config = decodeAcpConfig(execution.config);
49
49
  const drive = async (input, custody) => {
50
+ if (input.runtimeInstructions !== undefined) {
51
+ throw new Error("ACP has no verified native runtime-instruction channel; call with bare to omit the Keiyaku section");
52
+ }
50
53
  const launch = {
51
54
  argv: argv(execution, config, input.options),
52
55
  ...(execution.env === undefined ? {} : { env: execution.env }),
@@ -54,24 +54,27 @@ function claudeSessionId(coordinate) {
54
54
  return coordinate.sessionId;
55
55
  }
56
56
  function claudeQueryOptions(input, execution, abortController) {
57
+ const instructions = [input.options.systemPrompt, input.runtimeInstructions]
58
+ .filter((part) => part !== undefined && part.length > 0)
59
+ .join("\n\n");
57
60
  return {
58
61
  ...(execution.config ?? {}),
59
62
  cwd: input.cwd,
60
63
  abortController,
61
64
  ...(input.requests === undefined ? {} : { additionalDirectories: [input.requests.dir] }),
62
65
  ...(execution.executable === undefined ? {} : { pathToClaudeCodeExecutable: execution.executable }),
63
- env: akumaExecutionEnvironment(process.env, execution.env, input.requests?.dir),
66
+ env: akumaExecutionEnvironment(process.env, execution.env, input.requests?.dir, [], input.execution),
64
67
  permissionMode: "bypassPermissions",
65
68
  allowDangerouslySkipPermissions: true,
66
69
  settingSources: ["user", "project", "local"],
67
70
  ...(input.options.model === undefined ? {} : { model: input.options.model }),
68
71
  ...(input.options.effort === undefined ? {} : { effort: input.options.effort }),
69
- ...(input.options.systemPrompt === undefined || input.options.systemPrompt.length === 0
72
+ ...(instructions.length === 0
70
73
  ? {}
71
74
  : {
72
- systemPrompt: input.options.systemPromptMode === "replace"
73
- ? input.options.systemPrompt
74
- : { type: "preset", preset: "claude_code", append: input.options.systemPrompt },
75
+ systemPrompt: input.options.systemPromptMode === "replace" && (input.options.systemPrompt?.length ?? 0) > 0
76
+ ? instructions
77
+ : { type: "preset", preset: "claude_code", append: instructions },
75
78
  }),
76
79
  ...(input.session.kind === "fresh" ? {} : { resume: claudeSessionId(input.session.coordinate) }),
77
80
  ...(input.schemaJson === undefined
@@ -0,0 +1,5 @@
1
+ import { LineRpcProcess } from "../../../runtime/proc/line-rpc.js";
2
+ import { type ProviderExecution } from "../../provider-recipe.js";
3
+ export declare function initializeCodex(server: LineRpcProcess): Promise<void>;
4
+ /** Native config precedence belongs to Codex, including profiles and dotted overrides. */
5
+ export declare function withCodexWritableDirectories(execution: ProviderExecution, cwd: string, directories: readonly string[], signal?: AbortSignal): Promise<ProviderExecution>;
@@ -0,0 +1,72 @@
1
+ import { LineRpcProcess } from "../../../runtime/proc/line-rpc.js";
2
+ import { createProviderAttempt } from "../../provider.js";
3
+ import { decodeProviderRecipe } from "../../provider-recipe.js";
4
+ import { akumaExecutionEnvironment } from "../execution-environment.js";
5
+ import { codexObject } from "./events.js";
6
+ export async function initializeCodex(server) {
7
+ await server.request("initialize", {
8
+ clientInfo: { name: "keiyaku", title: "keiyaku", version: "4" },
9
+ capabilities: { experimentalApi: true, requestAttestation: false },
10
+ });
11
+ server.notify("initialized");
12
+ }
13
+ /** Native config precedence belongs to Codex, including profiles and dotted overrides. */
14
+ export async function withCodexWritableDirectories(execution, cwd, directories, signal) {
15
+ const attempt = createProviderAttempt(signal, async (custody) => {
16
+ custody.signal.throwIfAborted();
17
+ const server = new LineRpcProcess({
18
+ argv: [execution.executable ?? "codex", "app-server", "--listen", "stdio://"],
19
+ cwd,
20
+ env: akumaExecutionEnvironment(process.env, execution.env),
21
+ });
22
+ const closed = new Promise((resolve) => server.onExit(() => resolve()));
23
+ custody.own({ closed, forceDispose: () => server.close(true) });
24
+ try {
25
+ custody.signal.throwIfAborted();
26
+ await initializeCodex(server);
27
+ const response = codexObject(await server.request("thread/start", {
28
+ cwd,
29
+ ephemeral: true,
30
+ ...(execution.config === undefined ? {} : { config: execution.config }),
31
+ }));
32
+ custody.signal.throwIfAborted();
33
+ const sandbox = codexObject(response?.sandbox);
34
+ if (sandbox?.type !== "workspaceWrite" || response?.activePermissionProfile != null)
35
+ throw new TypeError("writableDirectories requires Codex native workspace-write sandbox configuration");
36
+ const roots = sandbox.writableRoots;
37
+ if (!Array.isArray(roots) ||
38
+ !roots.every((root) => typeof root === "string") ||
39
+ typeof sandbox.networkAccess !== "boolean" ||
40
+ typeof sandbox.excludeTmpdirEnvVar !== "boolean" ||
41
+ typeof sandbox.excludeSlashTmp !== "boolean")
42
+ throw new TypeError("Codex did not return its effective workspace-write configuration");
43
+ const config = { ...execution.config };
44
+ // Remove conflicting spellings of only the fields this native snapshot owns.
45
+ for (const key of ["writable_roots", "network_access", "exclude_tmpdir_env_var", "exclude_slash_tmp"])
46
+ delete config[`sandbox_workspace_write.${key}`];
47
+ return decodeProviderRecipe({
48
+ ...execution,
49
+ config: {
50
+ ...config,
51
+ sandbox_mode: "workspace-write",
52
+ sandbox_workspace_write: {
53
+ ...codexObject(config.sandbox_workspace_write),
54
+ writable_roots: [...new Set([...roots, ...directories])],
55
+ network_access: sandbox.networkAccess,
56
+ exclude_tmpdir_env_var: sandbox.excludeTmpdirEnvVar,
57
+ exclude_slash_tmp: sandbox.excludeSlashTmp,
58
+ },
59
+ },
60
+ });
61
+ }
62
+ finally {
63
+ await server.endInputAndDrain();
64
+ }
65
+ });
66
+ try {
67
+ return await attempt.result;
68
+ }
69
+ finally {
70
+ await attempt.closed;
71
+ }
72
+ }
@@ -3,17 +3,11 @@ import { AgentEventChannel, createProviderAttempt, launchPrompt, modelEvent, } f
3
3
  import { akumaExecutionEnvironment } from "../execution-environment.js";
4
4
  import { providerLifecycle } from "../lifecycle.js";
5
5
  import { codexNotificationResult, codexObject, codexText } from "./events.js";
6
+ import { initializeCodex } from "./configuration.js";
6
7
  export { CODEX_ITEM_DISPOSITIONS, CODEX_NOTIFICATION_DISPOSITIONS } from "./events.js";
7
8
  function diagnostic(error) {
8
9
  return error instanceof Error ? error.message : String(error);
9
10
  }
10
- async function initialize(server) {
11
- await server.request("initialize", {
12
- clientInfo: { name: "keiyaku", title: "keiyaku", version: "4" },
13
- capabilities: { experimentalApi: false, requestAttestation: false },
14
- });
15
- server.notify("initialized");
16
- }
17
11
  function threadId(result, fallback) {
18
12
  const value = codexObject(result);
19
13
  const thread = codexObject(value?.thread) ?? value;
@@ -56,7 +50,7 @@ async function steerTurn(server, state, tell) {
56
50
  return { kind: "accepted", fence: `${accepted}:${tell.id}` };
57
51
  }
58
52
  async function admitTurn(server, input, state, events, config) {
59
- await initialize(server);
53
+ await initializeCodex(server);
60
54
  const threadParams = {
61
55
  cwd: input.cwd,
62
56
  ...(config === undefined ? {} : { config }),
@@ -90,6 +84,9 @@ async function admitTurn(server, input, state, events, config) {
90
84
  ...(input.options.model === undefined ? {} : { model: input.options.model }),
91
85
  ...(input.options.effort === undefined ? {} : { effort: input.options.effort }),
92
86
  approvalPolicy: "never",
87
+ ...(input.runtimeInstructions === undefined
88
+ ? {}
89
+ : { additionalContext: { keiyaku_execution: { kind: "application", value: input.runtimeInstructions } } }),
93
90
  ...(input.schemaJson === undefined ? {} : { outputSchema: JSON.parse(input.schemaJson) }),
94
91
  }));
95
92
  }
@@ -108,7 +105,7 @@ async function forkCodex(execution, input, custody) {
108
105
  forceDispose: async () => await server.close(true),
109
106
  });
110
107
  try {
111
- await initialize(server);
108
+ await initializeCodex(server);
112
109
  const child = threadId(await server.request("thread/fork", {
113
110
  threadId: input.session.sessionId,
114
111
  lastTurnId: input.at,
@@ -130,7 +127,7 @@ function codexServer(execution, input) {
130
127
  return new LineRpcProcess({
131
128
  argv: [execution.executable ?? "codex", "app-server", "--listen", "stdio://"],
132
129
  cwd: input.cwd,
133
- env: akumaExecutionEnvironment(process.env, execution.env, input.requests?.dir),
130
+ env: akumaExecutionEnvironment(process.env, execution.env, input.requests?.dir, [], input.execution),
134
131
  });
135
132
  }
136
133
  async function startCodex(execution, input, custody) {
@@ -1,7 +1,13 @@
1
1
  export declare const AKUMA_REQUESTS_ENV = "AKUMA_REQUESTS";
2
2
  export declare const AKUMA_REQUESTS_ENTRY_ENV = "AKUMA_REQUESTS_ENTRY";
3
- declare const PARENT_HARNESS_IDENTITY_KEYS: readonly ["CLAUDE_CODE_SESSION_ID", "CLAUDE_CODE_CHILD_SESSION", "CLAUDECODE", "CODEX_THREAD_ID", "OPENCODE_SESSION_ID", "PI_SESSION_ID", "PI_SESSION_FILE", "PASEO_AGENT_ID", "SQUARE_PARTICIPANT_NAME", "KEIYAKU_INITIATOR", "KEIYAKU_EXTERNAL_CALLER"];
3
+ export type ExecutionCoordinate = Readonly<{
4
+ akumaId: string;
5
+ world: string;
6
+ bodySequence: number;
7
+ turnSequence: number;
8
+ }>;
9
+ declare const PARENT_HARNESS_IDENTITY_KEYS: readonly ["KEIYAKU_BODY_SEQUENCE", "KEIYAKU_TURN_SEQUENCE", "CLAUDE_CODE_SESSION_ID", "CLAUDE_CODE_CHILD_SESSION", "CLAUDECODE", "CODEX_THREAD_ID", "OPENCODE_SESSION_ID", "PI_SESSION_ID", "PI_SESSION_FILE", "PASEO_AGENT_ID", "SQUARE_PARTICIPANT_NAME", "KEIYAKU_INITIATOR", "KEIYAKU_EXTERNAL_CALLER"];
4
10
  type Environment = Readonly<Record<string, string | undefined>>;
5
11
  /** Construct the environment for one isolated Akuma execution or native child. */
6
- export declare function akumaExecutionEnvironment(inherited: Environment, overrides?: Environment, requests?: string, nativeIdentity?: readonly (typeof PARENT_HARNESS_IDENTITY_KEYS)[number][]): Record<string, string>;
12
+ export declare function akumaExecutionEnvironment(inherited: Environment, overrides?: Environment, requests?: string, nativeIdentity?: readonly (typeof PARENT_HARNESS_IDENTITY_KEYS)[number][], execution?: ExecutionCoordinate): Record<string, string>;
7
13
  export {};
@@ -1,6 +1,8 @@
1
1
  export const AKUMA_REQUESTS_ENV = "AKUMA_REQUESTS";
2
2
  export const AKUMA_REQUESTS_ENTRY_ENV = "AKUMA_REQUESTS_ENTRY";
3
3
  const PARENT_HARNESS_IDENTITY_KEYS = [
4
+ "KEIYAKU_BODY_SEQUENCE",
5
+ "KEIYAKU_TURN_SEQUENCE",
4
6
  "CLAUDE_CODE_SESSION_ID",
5
7
  "CLAUDE_CODE_CHILD_SESSION",
6
8
  "CLAUDECODE",
@@ -14,7 +16,7 @@ const PARENT_HARNESS_IDENTITY_KEYS = [
14
16
  "KEIYAKU_EXTERNAL_CALLER",
15
17
  ];
16
18
  /** Construct the environment for one isolated Akuma execution or native child. */
17
- export function akumaExecutionEnvironment(inherited, overrides = {}, requests, nativeIdentity = []) {
19
+ export function akumaExecutionEnvironment(inherited, overrides = {}, requests, nativeIdentity = [], execution) {
18
20
  const preserved = Object.fromEntries(nativeIdentity.flatMap((key) => (inherited[key] === undefined ? [] : [[key, inherited[key]]])));
19
21
  const environment = Object.fromEntries(Object.entries({ ...inherited, ...overrides }).flatMap(([key, value]) => value === undefined ? [] : [[key, value]]));
20
22
  for (const key of PARENT_HARNESS_IDENTITY_KEYS)
@@ -24,5 +26,12 @@ export function akumaExecutionEnvironment(inherited, overrides = {}, requests, n
24
26
  delete environment[AKUMA_REQUESTS_ENTRY_ENV];
25
27
  if (requests !== undefined)
26
28
  environment[AKUMA_REQUESTS_ENV] = requests;
29
+ if (execution !== undefined)
30
+ Object.assign(environment, {
31
+ KEIYAKU_ACTOR_ID: execution.akumaId,
32
+ KEIYAKU_ACTOR_WORLD: execution.world,
33
+ KEIYAKU_BODY_SEQUENCE: String(execution.bodySequence),
34
+ KEIYAKU_TURN_SEQUENCE: String(execution.turnSequence),
35
+ });
27
36
  return environment;
28
37
  }
@@ -65,24 +65,31 @@ function optionAdmission(options) {
65
65
  options,
66
66
  };
67
67
  }
68
- function grokSessionMeta(config, options) {
69
- // Keiyaku does not implement Grok's reverse ask_user_question request, so
70
- // keep that unsupported tool out of every session's advertised toolset.
68
+ function grokSessionMeta(config, input) {
69
+ // Grok appends rules only when creating a session; ordinary load preserves
70
+ // that immutable execution context without requiring a hot-update channel.
71
+ const options = input.options;
71
72
  const sessionMeta = { ...(config ?? {}), askUserQuestion: false };
72
- const configured = { freshSessionMeta: sessionMeta, loadSessionMeta: sessionMeta };
73
- if (options.systemPrompt === undefined || options.systemPrompt.length === 0)
74
- return configured;
75
- if (options.systemPromptMode === "append")
76
- return { ...configured, freshSessionMeta: { ...sessionMeta, rules: options.systemPrompt } };
77
- if (options.systemPromptMode === "replace") {
78
- const meta = { systemPromptOverride: options.systemPrompt };
79
- return {
80
- ...configured,
81
- freshSessionMeta: { ...sessionMeta, ...meta },
82
- loadSessionMeta: { ...sessionMeta, ...meta },
73
+ const replacement = options.systemPromptMode === "replace" && options.systemPrompt?.trim()
74
+ ? options.systemPrompt
75
+ : typeof config?.systemPromptOverride === "string" && config.systemPromptOverride.trim()
76
+ ? config.systemPromptOverride
77
+ : undefined;
78
+ if (replacement !== undefined) {
79
+ const meta = {
80
+ ...sessionMeta,
81
+ systemPromptOverride: [replacement, input.runtimeInstructions].filter((part) => part !== undefined).join("\n\n"),
83
82
  };
83
+ return { freshSessionMeta: meta, loadSessionMeta: meta };
84
84
  }
85
- return configured;
85
+ const rules = options.systemPromptMode === "append" ? options.systemPrompt : config?.rules;
86
+ const appended = [typeof rules === "string" ? rules : undefined, input.runtimeInstructions]
87
+ .filter((part) => part !== undefined && part.length > 0)
88
+ .join("\n\n");
89
+ return {
90
+ freshSessionMeta: { ...sessionMeta, ...(appended === "" ? {} : { rules: appended }) },
91
+ loadSessionMeta: sessionMeta,
92
+ };
86
93
  }
87
94
  function argv(execution, options) {
88
95
  if (execution.executable === undefined)
@@ -127,7 +134,7 @@ export function createGrokBuildProvider(execution, dependencies = {}) {
127
134
  argv: argv(execution, input.options),
128
135
  ...(execution.env === undefined ? {} : { env: execution.env }),
129
136
  };
130
- const sessionMeta = grokSessionMeta(execution.config, input.options);
137
+ const sessionMeta = grokSessionMeta(execution.config, input);
131
138
  live = await startAcpSession(launch, input, {
132
139
  ...dependencies,
133
140
  configureClient: (client) => {
@@ -1,6 +1,7 @@
1
1
  import type { ProviderAdapter } from "../provider.js";
2
2
  import type { ProviderExecution } from "../provider-recipe.js";
3
3
  export { decodeProviderRecipe as decodeProviderExecution } from "../provider-recipe.js";
4
+ export declare function withWritableDirectories(execution: ProviderExecution, cwd: string, directories: readonly string[], signal?: AbortSignal): Promise<ProviderExecution>;
4
5
  export declare function resolveProviderExecution(execution: ProviderExecution): Promise<Readonly<{
5
6
  execution: ProviderExecution;
6
7
  adapter: ProviderAdapter;
@@ -20,6 +20,14 @@ async function adapterFor(execution) {
20
20
  return (await import("./pi/index.js")).createPiProvider(execution);
21
21
  throw new TypeError(`unknown Akuma provider kind ${execution.kind}`);
22
22
  }
23
+ export async function withWritableDirectories(execution, cwd, directories, signal) {
24
+ if (directories.length === 0)
25
+ return execution;
26
+ if (execution.kind !== "codex-app-server")
27
+ throw new TypeError(`writableDirectories is unsupported by provider ${execution.kind}`);
28
+ const { withCodexWritableDirectories } = await import("./codex-app-server/configuration.js");
29
+ return await withCodexWritableDirectories(execution, cwd, directories, signal);
30
+ }
23
31
  export async function resolveProviderExecution(execution) {
24
32
  return Object.freeze({ execution, adapter: await adapterFor(execution) });
25
33
  }
@@ -181,6 +181,14 @@ async function configureSession(runtime, input, id, info, model) {
181
181
  // and fork. Updating the same entry announces an upstream instruction change.
182
182
  await session.instructions({ id, text: input.options.systemPrompt });
183
183
  }
184
+ if (input.runtimeInstructions === undefined) {
185
+ // Native forks copy current entries. Absence must remove the inherited
186
+ // runtime entry, not leave the source identity active in a bare child.
187
+ await session.removeInstruction({ id, key: "keiyaku.runtime" });
188
+ }
189
+ else {
190
+ await session.instructions({ id, key: "keiyaku.runtime", text: input.runtimeInstructions });
191
+ }
184
192
  }
185
193
  async function openSession(runtime, input) {
186
194
  const model = input.options.model === undefined
@@ -217,6 +225,7 @@ async function openResources(execution, input, loader, custody) {
217
225
  onRuntime: (ready) => {
218
226
  runtimeOwner = ownRuntime(custody, ready);
219
227
  },
228
+ ...(input.execution === undefined ? {} : { executionCoordinate: input.execution }),
220
229
  ...(input.requests === undefined ? {} : { requests: input.requests.dir }),
221
230
  });
222
231
  const stream = ownEventStream({
@@ -15,6 +15,11 @@ export type OpencodeSdkSession = Readonly<{
15
15
  instructions(input: {
16
16
  id: string;
17
17
  text: string;
18
+ key?: string;
19
+ }): Promise<unknown>;
20
+ removeInstruction(input: {
21
+ id: string;
22
+ key: string;
18
23
  }): Promise<unknown>;
19
24
  active(): Promise<unknown>;
20
25
  fork(input: {
@@ -75,6 +80,7 @@ type LoadOpencodeInput = Readonly<{
75
80
  signal: AbortSignal;
76
81
  loader?: OpencodeSdkLoader;
77
82
  onRuntime?: (runtime: OpencodeRuntime) => void;
83
+ executionCoordinate?: import("../execution-environment.js").ExecutionCoordinate;
78
84
  requests?: string;
79
85
  }>;
80
86
  export declare function loadOpencode(input: LoadOpencodeInput): Promise<OpencodeRuntime>;
@@ -80,7 +80,7 @@ async function loadInjectedOpencode(input, loader) {
80
80
  const { execution, cwd, signal, onRuntime, requests } = input;
81
81
  const loaded = await abortable(loader(cwd, {
82
82
  ...execution,
83
- env: akumaExecutionEnvironment(process.env, execution.env, requests),
83
+ env: akumaExecutionEnvironment(process.env, execution.env, requests, [], input.executionCoordinate),
84
84
  }, signal), signal);
85
85
  let closing;
86
86
  const runtime = {
@@ -117,7 +117,7 @@ async function loadNativeOpencode(input) {
117
117
  ...execution.env,
118
118
  OPENCODE_PASSWORD: password,
119
119
  OPENCODE_SERVER_PASSWORD: password,
120
- }, requests),
120
+ }, requests, [], input.executionCoordinate),
121
121
  log: `${cwd}/.opencode.log`,
122
122
  });
123
123
  const native = createNativeClient(`http://127.0.0.1:${port}`, password);
@@ -129,7 +129,8 @@ async function loadNativeOpencode(input) {
129
129
  create: async ({ body }) => ({ data: await native.sdk.session.create(body, options) }),
130
130
  get: async ({ id }) => ({ data: await native.sdk.session.get({ sessionID: id }, options) }),
131
131
  switchModel: ({ id, model }) => native.sdk.session.switchModel({ sessionID: id, model }, options),
132
- instructions: ({ id, text }) => native.sdk.session.instructions.entry.put({ sessionID: id, key: "keiyaku.system", value: text }, options),
132
+ instructions: ({ id, text, key = "keiyaku.system" }) => native.sdk.session.instructions.entry.put({ sessionID: id, key, value: text }, options),
133
+ removeInstruction: ({ id, key }) => native.sdk.session.instructions.entry.remove({ sessionID: id, key }, options),
133
134
  active: async () => ({ data: await native.sdk.session.active(options) }),
134
135
  fork: async ({ id, before }) => ({ data: await native.sdk.session.fork({ sessionID: id, before }, options) }),
135
136
  interrupt: ({ id }) => native.sdk.session.interrupt({ sessionID: id, resume: false }),
@@ -207,6 +207,9 @@ class PaseoDrive {
207
207
  });
208
208
  }
209
209
  async establish(input, config, coordinate) {
210
+ const systemPrompt = [input.options.systemPrompt, input.runtimeInstructions]
211
+ .filter((part) => part !== undefined && part.length > 0)
212
+ .join("\n\n");
210
213
  const entry = input.requests.entry;
211
214
  if (entry === undefined || !isAbsolute(entry) || resolve(entry) !== entry)
212
215
  throw new Error("Paseo requires the Body's stable request entry");
@@ -216,8 +219,11 @@ class PaseoDrive {
216
219
  ? await setup(input.signal, () => this.client.createAgent({
217
220
  provider: config.provider,
218
221
  cwd: input.cwd,
219
- ...(input.options.systemPrompt === undefined ? {} : { systemPrompt: input.options.systemPrompt }),
220
- env: { ...akumaExecutionEnvironment(process.env, this.environment), [AKUMA_REQUESTS_ENTRY_ENV]: entry },
222
+ ...(systemPrompt === "" ? {} : { systemPrompt }),
223
+ env: {
224
+ ...akumaExecutionEnvironment(process.env, this.environment, undefined, [], input.execution),
225
+ [AKUMA_REQUESTS_ENTRY_ENV]: entry,
226
+ },
221
227
  autoArchive: false,
222
228
  }))
223
229
  : await this.existingAgent(coordinate, input.signal);