@earendil-works/pi-coding-agent 0.85.0 → 0.85.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 +18 -0
- package/README.md +0 -2
- package/dist/bun/cli.d.ts +3 -1
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +3 -12
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/sandbox-env-setup.d.ts +2 -0
- package/dist/bun/sandbox-env-setup.d.ts.map +1 -0
- package/dist/bun/sandbox-env-setup.js +4 -0
- package/dist/bun/sandbox-env-setup.js.map +1 -0
- package/dist/bundle/chunks/{anthropic-messages-QAQLEQIY.js → anthropic-messages-VWZZOSJQ.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-Q7MJBRE6.js → azure-openai-responses-BJLAM6CD.js} +1 -1
- package/dist/bundle/chunks/{chunk-R7UUJ4C2.js → chunk-CLNPYIDP.js} +1 -1
- package/dist/bundle/chunks/chunk-JVUZSMYM.js +1547 -0
- package/dist/bundle/chunks/{chunk-2KVJKXS2.js → chunk-U6ZMQKGD.js} +1 -1
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-BSMTYDAM.js → google-generative-ai-Q2K7FBDI.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-5C3HASOJ.js → google-vertex-7UJBF4S7.js} +1 -1
- package/dist/bundle/chunks/{node-EM5FIVUN.js → node-KG362ECQ.js} +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-YJOO52RW.js → openai-codex-responses-R6VYZTVY.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-QOT3QX7D.js → openai-completions-EKZT2IH2.js} +1 -1
- package/dist/bundle/chunks/openai-responses-TFDINO6W.js +2 -0
- package/dist/bundle/chunks/{pi-messages-EGZIFQGG.js → pi-messages-PML4SPVJ.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +0 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/setup.d.ts +2 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +12 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -25
- package/dist/cli.js.map +1 -1
- package/dist/core/keybindings.d.ts +5 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +4 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +0 -122
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +5 -5
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +8 -8
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +4 -4
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/docs/containerization.md +45 -0
- package/docs/development.md +19 -0
- package/docs/environment-variables.md +2 -2
- package/docs/keybindings.md +2 -1
- package/docs/models.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +20 -46
- package/package.json +13 -12
- package/dist/bundle/chunks/chunk-EQ6DR6XK.js +0 -5
- package/dist/bundle/chunks/chunk-LZKJTKCT.js +0 -2
- package/dist/bundle/chunks/chunk-WBE4J4AU.js +0 -9
- package/dist/bundle/chunks/chunk-WZB2R5YO.js +0 -1558
- package/dist/bundle/chunks/openai-responses-U7LNPQN4.js +0 -2
- package/dist/bundle/client.js +0 -2
- package/dist/bundle/coordinator.js +0 -3
- package/dist/cli/experimental/cli.d.ts +0 -10
- package/dist/cli/experimental/cli.d.ts.map +0 -1
- package/dist/cli/experimental/cli.js +0 -9
- package/dist/cli/experimental/cli.js.map +0 -1
- package/dist/cli/experimental/command-options.d.ts +0 -28
- package/dist/cli/experimental/command-options.d.ts.map +0 -1
- package/dist/cli/experimental/command-options.js +0 -84
- package/dist/cli/experimental/command-options.js.map +0 -1
- package/dist/cli/experimental/command.d.ts +0 -70
- package/dist/cli/experimental/command.d.ts.map +0 -1
- package/dist/cli/experimental/command.js +0 -144
- package/dist/cli/experimental/command.js.map +0 -1
- package/dist/cli/experimental/commands/client.d.ts +0 -19
- package/dist/cli/experimental/commands/client.d.ts.map +0 -1
- package/dist/cli/experimental/commands/client.js +0 -63
- package/dist/cli/experimental/commands/client.js.map +0 -1
- package/dist/cli/experimental/commands/server.d.ts +0 -17
- package/dist/cli/experimental/commands/server.d.ts.map +0 -1
- package/dist/cli/experimental/commands/server.js +0 -44
- package/dist/cli/experimental/commands/server.js.map +0 -1
- package/dist/client/index.d.ts +0 -2
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js +0 -2
- package/dist/client/index.js.map +0 -1
- package/dist/experimental/client-runtime.d.ts +0 -43
- package/dist/experimental/client-runtime.d.ts.map +0 -1
- package/dist/experimental/client-runtime.js +0 -183
- package/dist/experimental/client-runtime.js.map +0 -1
- package/dist/experimental/client-tui-chat.d.ts +0 -14
- package/dist/experimental/client-tui-chat.d.ts.map +0 -1
- package/dist/experimental/client-tui-chat.js +0 -171
- package/dist/experimental/client-tui-chat.js.map +0 -1
- package/dist/experimental/client-tui.d.ts +0 -37
- package/dist/experimental/client-tui.d.ts.map +0 -1
- package/dist/experimental/client-tui.js +0 -702
- package/dist/experimental/client-tui.js.map +0 -1
- package/dist/experimental/client.d.ts +0 -25
- package/dist/experimental/client.d.ts.map +0 -1
- package/dist/experimental/client.js +0 -99
- package/dist/experimental/client.js.map +0 -1
- package/dist/experimental/coordinator-entry.d.ts +0 -3
- package/dist/experimental/coordinator-entry.d.ts.map +0 -1
- package/dist/experimental/coordinator-entry.js +0 -11
- package/dist/experimental/coordinator-entry.js.map +0 -1
- package/dist/experimental/coordinator.d.ts +0 -38
- package/dist/experimental/coordinator.d.ts.map +0 -1
- package/dist/experimental/coordinator.js +0 -570
- package/dist/experimental/coordinator.js.map +0 -1
- package/dist/experimental/mini/main.d.ts +0 -7
- package/dist/experimental/mini/main.d.ts.map +0 -1
- package/dist/experimental/mini/main.js +0 -21
- package/dist/experimental/mini/main.js.map +0 -1
- package/dist/experimental/mini/server/entry.d.ts +0 -3
- package/dist/experimental/mini/server/entry.d.ts.map +0 -1
- package/dist/experimental/mini/server/entry.js +0 -11
- package/dist/experimental/mini/server/entry.js.map +0 -1
- package/dist/experimental/mini/server/run.d.ts +0 -13
- package/dist/experimental/mini/server/run.d.ts.map +0 -1
- package/dist/experimental/mini/server/run.js +0 -150
- package/dist/experimental/mini/server/run.js.map +0 -1
- package/dist/experimental/mini/shared/protocol.d.ts +0 -127
- package/dist/experimental/mini/shared/protocol.d.ts.map +0 -1
- package/dist/experimental/mini/shared/protocol.js +0 -13
- package/dist/experimental/mini/shared/protocol.js.map +0 -1
- package/dist/experimental/mini/shared/rpc.d.ts +0 -49
- package/dist/experimental/mini/shared/rpc.d.ts.map +0 -1
- package/dist/experimental/mini/shared/rpc.js +0 -171
- package/dist/experimental/mini/shared/rpc.js.map +0 -1
- package/dist/experimental/mini/shared/transport.d.ts +0 -35
- package/dist/experimental/mini/shared/transport.d.ts.map +0 -1
- package/dist/experimental/mini/shared/transport.js +0 -94
- package/dist/experimental/mini/shared/transport.js.map +0 -1
- package/dist/experimental/mini/tui/run.d.ts +0 -9
- package/dist/experimental/mini/tui/run.d.ts.map +0 -1
- package/dist/experimental/mini/tui/run.js +0 -62
- package/dist/experimental/mini/tui/run.js.map +0 -1
- package/dist/experimental/mini/tui/session.d.ts +0 -26
- package/dist/experimental/mini/tui/session.d.ts.map +0 -1
- package/dist/experimental/mini/tui/session.js +0 -94
- package/dist/experimental/mini/tui/session.js.map +0 -1
- package/dist/experimental/mini/tui/view.d.ts +0 -10
- package/dist/experimental/mini/tui/view.d.ts.map +0 -1
- package/dist/experimental/mini/tui/view.js +0 -459
- package/dist/experimental/mini/tui/view.js.map +0 -1
- package/dist/experimental/mini/worker/entry.d.ts +0 -3
- package/dist/experimental/mini/worker/entry.d.ts.map +0 -1
- package/dist/experimental/mini/worker/entry.js +0 -10
- package/dist/experimental/mini/worker/entry.js.map +0 -1
- package/dist/experimental/mini/worker/lane-service.d.ts +0 -44
- package/dist/experimental/mini/worker/lane-service.d.ts.map +0 -1
- package/dist/experimental/mini/worker/lane-service.js +0 -97
- package/dist/experimental/mini/worker/lane-service.js.map +0 -1
- package/dist/experimental/mini/worker/models-service.d.ts +0 -19
- package/dist/experimental/mini/worker/models-service.d.ts.map +0 -1
- package/dist/experimental/mini/worker/models-service.js +0 -136
- package/dist/experimental/mini/worker/models-service.js.map +0 -1
- package/dist/experimental/mini/worker/run.d.ts +0 -14
- package/dist/experimental/mini/worker/run.d.ts.map +0 -1
- package/dist/experimental/mini/worker/run.js +0 -88
- package/dist/experimental/mini/worker/run.js.map +0 -1
- package/dist/experimental/plugin.d.ts +0 -4
- package/dist/experimental/plugin.d.ts.map +0 -1
- package/dist/experimental/plugin.js +0 -4
- package/dist/experimental/plugin.js.map +0 -1
- package/dist/experimental/plugins/bundled.d.ts +0 -7
- package/dist/experimental/plugins/bundled.d.ts.map +0 -1
- package/dist/experimental/plugins/bundled.js +0 -48
- package/dist/experimental/plugins/bundled.js.map +0 -1
- package/dist/experimental/plugins/package.d.ts +0 -18
- package/dist/experimental/plugins/package.d.ts.map +0 -1
- package/dist/experimental/plugins/package.js +0 -113
- package/dist/experimental/plugins/package.js.map +0 -1
- package/dist/experimental/process.d.ts +0 -20
- package/dist/experimental/process.d.ts.map +0 -1
- package/dist/experimental/process.js +0 -85
- package/dist/experimental/process.js.map +0 -1
- package/dist/experimental/radius-auth.d.ts +0 -17
- package/dist/experimental/radius-auth.d.ts.map +0 -1
- package/dist/experimental/radius-auth.js +0 -52
- package/dist/experimental/radius-auth.js.map +0 -1
- package/dist/experimental/radius-relay.d.ts +0 -90
- package/dist/experimental/radius-relay.d.ts.map +0 -1
- package/dist/experimental/radius-relay.js +0 -582
- package/dist/experimental/radius-relay.js.map +0 -1
- package/dist/experimental/server.d.ts +0 -75
- package/dist/experimental/server.d.ts.map +0 -1
- package/dist/experimental/server.js +0 -682
- package/dist/experimental/server.js.map +0 -1
- package/dist/experimental/services/agent-controller-provider.d.ts +0 -4
- package/dist/experimental/services/agent-controller-provider.d.ts.map +0 -1
- package/dist/experimental/services/agent-controller-provider.js +0 -84
- package/dist/experimental/services/agent-controller-provider.js.map +0 -1
- package/dist/experimental/services/agent-controller.d.ts +0 -57
- package/dist/experimental/services/agent-controller.d.ts.map +0 -1
- package/dist/experimental/services/agent-controller.js +0 -3
- package/dist/experimental/services/agent-controller.js.map +0 -1
- package/dist/experimental/services/connection.d.ts +0 -40
- package/dist/experimental/services/connection.d.ts.map +0 -1
- package/dist/experimental/services/connection.js +0 -300
- package/dist/experimental/services/connection.js.map +0 -1
- package/dist/experimental/services/models-provider.d.ts +0 -16
- package/dist/experimental/services/models-provider.d.ts.map +0 -1
- package/dist/experimental/services/models-provider.js +0 -116
- package/dist/experimental/services/models-provider.js.map +0 -1
- package/dist/experimental/services/models.d.ts +0 -36
- package/dist/experimental/services/models.d.ts.map +0 -1
- package/dist/experimental/services/models.js +0 -3
- package/dist/experimental/services/models.js.map +0 -1
- package/dist/experimental/services/plugins.d.ts +0 -16
- package/dist/experimental/services/plugins.d.ts.map +0 -1
- package/dist/experimental/services/plugins.js +0 -4
- package/dist/experimental/services/plugins.js.map +0 -1
- package/dist/experimental/services/presentation-ui.d.ts +0 -13
- package/dist/experimental/services/presentation-ui.d.ts.map +0 -1
- package/dist/experimental/services/presentation-ui.js +0 -3
- package/dist/experimental/services/presentation-ui.js.map +0 -1
- package/dist/experimental/services/server.d.ts +0 -19
- package/dist/experimental/services/server.d.ts.map +0 -1
- package/dist/experimental/services/server.js +0 -104
- package/dist/experimental/services/server.js.map +0 -1
- package/dist/experimental/services/sessions.d.ts +0 -28
- package/dist/experimental/services/sessions.d.ts.map +0 -1
- package/dist/experimental/services/sessions.js +0 -4
- package/dist/experimental/services/sessions.js.map +0 -1
- package/dist/experimental/services/slash-commands-provider.d.ts +0 -14
- package/dist/experimental/services/slash-commands-provider.d.ts.map +0 -1
- package/dist/experimental/services/slash-commands-provider.js +0 -200
- package/dist/experimental/services/slash-commands-provider.js.map +0 -1
- package/dist/experimental/services/slash-commands.d.ts +0 -24
- package/dist/experimental/services/slash-commands.d.ts.map +0 -1
- package/dist/experimental/services/slash-commands.js +0 -3
- package/dist/experimental/services/slash-commands.js.map +0 -1
- package/dist/experimental/services/transcript-provider.d.ts +0 -12
- package/dist/experimental/services/transcript-provider.d.ts.map +0 -1
- package/dist/experimental/services/transcript-provider.js +0 -109
- package/dist/experimental/services/transcript-provider.js.map +0 -1
- package/dist/experimental/services/transcript.d.ts +0 -13
- package/dist/experimental/services/transcript.d.ts.map +0 -1
- package/dist/experimental/services/transcript.js +0 -3
- package/dist/experimental/services/transcript.js.map +0 -1
- package/dist/experimental/services/worker.d.ts +0 -28
- package/dist/experimental/services/worker.d.ts.map +0 -1
- package/dist/experimental/services/worker.js +0 -107
- package/dist/experimental/services/worker.js.map +0 -1
- package/dist/experimental/session-worker-manager.d.ts +0 -24
- package/dist/experimental/session-worker-manager.d.ts.map +0 -1
- package/dist/experimental/session-worker-manager.js +0 -691
- package/dist/experimental/session-worker-manager.js.map +0 -1
- package/dist/experimental/session-worker.d.ts +0 -188
- package/dist/experimental/session-worker.d.ts.map +0 -1
- package/dist/experimental/session-worker.js +0 -785
- package/dist/experimental/session-worker.js.map +0 -1
- package/dist/experimental/source-resolver.d.ts +0 -2
- package/dist/experimental/source-resolver.d.ts.map +0 -1
- package/dist/experimental/source-resolver.js +0 -71
- package/dist/experimental/source-resolver.js.map +0 -1
|
@@ -1,785 +0,0 @@
|
|
|
1
|
-
import { createConnection } from "node:net";
|
|
2
|
-
import { isAbsolute } from "node:path";
|
|
3
|
-
import { isJsonValue, parseServiceProviderUpdate, REMOTE_SERVICE_ERROR_CODES, RemoteServiceError, } from "@earendil-works/chord";
|
|
4
|
-
import { AgentHarness, BACKGROUND_CONTEXT, createBashTool, createReadTool, createWriteTool, JsonlSessionRepo, TODO_CONTEXT, withCancel, } from "@earendil-works/pi-agent-core";
|
|
5
|
-
import { NodeExecutionEnv } from "@earendil-works/pi-agent-core/node";
|
|
6
|
-
import lockfile from "proper-lockfile";
|
|
7
|
-
import Type from "typebox";
|
|
8
|
-
import { Check } from "typebox/value";
|
|
9
|
-
import { findInitialModel, resolveCliModel } from "../core/model-resolver.js";
|
|
10
|
-
import { ModelRuntime } from "../core/model-runtime.js";
|
|
11
|
-
import { SettingsManager } from "../core/settings-manager.js";
|
|
12
|
-
import { COORDINATOR_PROTOCOL_VERSION } from "./coordinator.js";
|
|
13
|
-
import { createSessionPluginFacetLoader } from "./plugins/bundled.js";
|
|
14
|
-
import { consumeInternalProcessRole, encodeControlLine, isDirectInternalProcessEntry, MAX_CONTROL_LINE_BYTES, } from "./process.js";
|
|
15
|
-
import { createSessionWorkerServices, } from "./services/worker.js";
|
|
16
|
-
const StrictObject = (properties) => Type.Object(properties, { additionalProperties: false });
|
|
17
|
-
const OpaqueJsonValueSchema = Type.Unsafe(Type.Unknown());
|
|
18
|
-
const ServiceCallSchema = Type.Unsafe(StrictObject({
|
|
19
|
-
serviceId: Type.String({ minLength: 1 }),
|
|
20
|
-
instance: Type.Optional(StrictObject({ key: Type.String({ minLength: 1 }), generation: Type.Integer({ minimum: 1 }) })),
|
|
21
|
-
member: Type.String({ minLength: 1 }),
|
|
22
|
-
args: Type.Array(Type.Unknown()),
|
|
23
|
-
}));
|
|
24
|
-
const RemoteServiceErrorCodeSchema = Type.Unsafe(Type.String({ pattern: `^(?:${REMOTE_SERVICE_ERROR_CODES.join("|")})$` }));
|
|
25
|
-
export const SESSION_WORKER_CONTROL_ADDRESS_ENV = "PI_SESSION_WORKER_CONTROL_ADDRESS";
|
|
26
|
-
export const SESSION_WORKER_CONTROL_TOKEN_ENV = "PI_SESSION_WORKER_CONTROL_TOKEN";
|
|
27
|
-
export const SESSION_WORKER_SESSION_KEY_ENV = "PI_SESSION_WORKER_SESSION_KEY_BASE64";
|
|
28
|
-
export const SESSION_WORKER_PEER_ID_ENV = "PI_SESSION_WORKER_PEER_ID";
|
|
29
|
-
export const SessionWorkerMetadataSchema = StrictObject({
|
|
30
|
-
id: Type.String({ minLength: 1 }),
|
|
31
|
-
createdAt: Type.Integer(),
|
|
32
|
-
storageVersion: Type.Integer(),
|
|
33
|
-
cwd: Type.String(),
|
|
34
|
-
path: Type.String(),
|
|
35
|
-
modifiedAt: Type.Number(),
|
|
36
|
-
parentSessionId: Type.Optional(Type.String()),
|
|
37
|
-
});
|
|
38
|
-
export const SessionWorkerOptionsSchema = StrictObject({
|
|
39
|
-
sessionDir: Type.String({ minLength: 1 }),
|
|
40
|
-
metadata: SessionWorkerMetadataSchema,
|
|
41
|
-
provider: Type.Optional(Type.String({ minLength: 1 })),
|
|
42
|
-
model: Type.Optional(Type.String({ minLength: 1 })),
|
|
43
|
-
pluginManifestPaths: Type.Array(Type.String({ minLength: 1 })),
|
|
44
|
-
});
|
|
45
|
-
export const WorkerOperationScopeSchema = StrictObject({
|
|
46
|
-
serverConnectionId: Type.String(),
|
|
47
|
-
attachmentId: Type.String(),
|
|
48
|
-
});
|
|
49
|
-
export const WorkerOperationRequestSchema = StrictObject({
|
|
50
|
-
type: Type.Literal("operation"),
|
|
51
|
-
requestId: Type.String({ minLength: 1 }),
|
|
52
|
-
scope: WorkerOperationScopeSchema,
|
|
53
|
-
call: ServiceCallSchema,
|
|
54
|
-
});
|
|
55
|
-
export const WorkerOperationResponseSchema = Type.Union([
|
|
56
|
-
StrictObject({
|
|
57
|
-
type: Type.Literal("operation_result"),
|
|
58
|
-
requestId: Type.String({ minLength: 1 }),
|
|
59
|
-
scope: WorkerOperationScopeSchema,
|
|
60
|
-
result: Type.Optional(OpaqueJsonValueSchema),
|
|
61
|
-
}),
|
|
62
|
-
StrictObject({
|
|
63
|
-
type: Type.Literal("operation_error"),
|
|
64
|
-
requestId: Type.String({ minLength: 1 }),
|
|
65
|
-
scope: WorkerOperationScopeSchema,
|
|
66
|
-
code: Type.Optional(RemoteServiceErrorCodeSchema),
|
|
67
|
-
message: Type.String(),
|
|
68
|
-
}),
|
|
69
|
-
]);
|
|
70
|
-
export const SessionWorkerCommandSchema = Type.Union([
|
|
71
|
-
Type.Object({ type: Type.Literal("shutdown") }),
|
|
72
|
-
Type.Object({ type: Type.Literal("discover_workers") }),
|
|
73
|
-
Type.Object({
|
|
74
|
-
type: Type.Literal("session_demand"),
|
|
75
|
-
serverConnectionId: Type.String(),
|
|
76
|
-
requestId: Type.String(),
|
|
77
|
-
attachmentId: Type.String(),
|
|
78
|
-
attached: Type.Boolean(),
|
|
79
|
-
}),
|
|
80
|
-
WorkerOperationRequestSchema,
|
|
81
|
-
StrictObject({
|
|
82
|
-
type: Type.Literal("operation_cancel"),
|
|
83
|
-
requestId: Type.String({ minLength: 1 }),
|
|
84
|
-
scope: WorkerOperationScopeSchema,
|
|
85
|
-
}),
|
|
86
|
-
]);
|
|
87
|
-
export const SessionWorkerEventSchema = Type.Union([
|
|
88
|
-
Type.Object({
|
|
89
|
-
type: Type.Literal("worker_ready"),
|
|
90
|
-
token: Type.String(),
|
|
91
|
-
sessionKey: Type.String(),
|
|
92
|
-
sessionId: Type.String(),
|
|
93
|
-
pid: Type.Integer({ minimum: 1 }),
|
|
94
|
-
metadata: SessionWorkerMetadataSchema,
|
|
95
|
-
pluginManifestPaths: Type.Array(Type.String({ minLength: 1 })),
|
|
96
|
-
}),
|
|
97
|
-
Type.Object({
|
|
98
|
-
type: Type.Literal("worker_failed"),
|
|
99
|
-
token: Type.String(),
|
|
100
|
-
sessionKey: Type.String(),
|
|
101
|
-
message: Type.String(),
|
|
102
|
-
}),
|
|
103
|
-
Type.Object({
|
|
104
|
-
type: Type.Literal("demand_applied"),
|
|
105
|
-
token: Type.String(),
|
|
106
|
-
sessionKey: Type.String(),
|
|
107
|
-
requestId: Type.String(),
|
|
108
|
-
attachmentId: Type.String(),
|
|
109
|
-
attached: Type.Boolean(),
|
|
110
|
-
}),
|
|
111
|
-
Type.Object({
|
|
112
|
-
type: Type.Literal("demand_rejected"),
|
|
113
|
-
token: Type.String(),
|
|
114
|
-
sessionKey: Type.String(),
|
|
115
|
-
requestId: Type.String(),
|
|
116
|
-
message: Type.String(),
|
|
117
|
-
}),
|
|
118
|
-
Type.Object({
|
|
119
|
-
type: Type.Literal("operation_response"),
|
|
120
|
-
token: Type.String(),
|
|
121
|
-
sessionKey: Type.String(),
|
|
122
|
-
response: WorkerOperationResponseSchema,
|
|
123
|
-
}),
|
|
124
|
-
Type.Object({
|
|
125
|
-
type: Type.Literal("service_update"),
|
|
126
|
-
token: Type.String(),
|
|
127
|
-
sessionKey: Type.String(),
|
|
128
|
-
scope: WorkerOperationScopeSchema,
|
|
129
|
-
subscriptionId: Type.String({ minLength: 1 }),
|
|
130
|
-
update: Type.Unknown(),
|
|
131
|
-
}),
|
|
132
|
-
]);
|
|
133
|
-
/** Worker-local reconciliation of server-generation demand and Harness activity. */
|
|
134
|
-
export class WorkerLifecycle {
|
|
135
|
-
#initialDemandGraceMs;
|
|
136
|
-
#orphanDemandGraceMs;
|
|
137
|
-
#onRetire;
|
|
138
|
-
#demands = new Map();
|
|
139
|
-
#activeOperations = new Set();
|
|
140
|
-
#currentServerConnectionId;
|
|
141
|
-
#initialTimer;
|
|
142
|
-
#demandInitialized;
|
|
143
|
-
#retirementHolds = 0;
|
|
144
|
-
#retiring = false;
|
|
145
|
-
constructor(options) {
|
|
146
|
-
this.#currentServerConnectionId = options.initialServerConnectionId;
|
|
147
|
-
this.#initialDemandGraceMs = options.initialDemandGraceMs;
|
|
148
|
-
this.#orphanDemandGraceMs = options.orphanDemandGraceMs;
|
|
149
|
-
this.#onRetire = options.onRetire;
|
|
150
|
-
this.#demandInitialized = false;
|
|
151
|
-
this.#initialTimer = setTimeout(() => {
|
|
152
|
-
this.#initialTimer = undefined;
|
|
153
|
-
this.#demandInitialized = true;
|
|
154
|
-
this.#reconcile();
|
|
155
|
-
}, this.#initialDemandGraceMs);
|
|
156
|
-
this.#initialTimer.unref();
|
|
157
|
-
}
|
|
158
|
-
serverConnected(serverConnectionId) {
|
|
159
|
-
this.#currentServerConnectionId = serverConnectionId;
|
|
160
|
-
for (const demand of this.#demands.values()) {
|
|
161
|
-
if (demand.serverConnectionId !== serverConnectionId || !demand.timer)
|
|
162
|
-
continue;
|
|
163
|
-
clearTimeout(demand.timer);
|
|
164
|
-
delete demand.timer;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
serverDisconnected(serverConnectionId) {
|
|
168
|
-
if (this.#currentServerConnectionId === serverConnectionId)
|
|
169
|
-
this.#currentServerConnectionId = undefined;
|
|
170
|
-
for (const [key, demand] of this.#demands) {
|
|
171
|
-
if (demand.serverConnectionId !== serverConnectionId || demand.timer)
|
|
172
|
-
continue;
|
|
173
|
-
demand.timer = setTimeout(() => {
|
|
174
|
-
if (this.#demands.get(key) !== demand)
|
|
175
|
-
return;
|
|
176
|
-
this.#demands.delete(key);
|
|
177
|
-
this.#reconcile();
|
|
178
|
-
}, this.#orphanDemandGraceMs);
|
|
179
|
-
demand.timer.unref();
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
beginRequest(serverConnectionId, attachmentId) {
|
|
183
|
-
if (this.#retiring)
|
|
184
|
-
throw new Error("Session worker is retiring");
|
|
185
|
-
if (serverConnectionId !== this.#currentServerConnectionId) {
|
|
186
|
-
throw new Error("Session worker received a request from a stale server generation");
|
|
187
|
-
}
|
|
188
|
-
const demand = this.#demands.get(demandKey(serverConnectionId, attachmentId));
|
|
189
|
-
if (!demand || demand.timer) {
|
|
190
|
-
throw new Error("Session worker request does not match the active attachment");
|
|
191
|
-
}
|
|
192
|
-
return this.holdRetirement();
|
|
193
|
-
}
|
|
194
|
-
holdRetirement() {
|
|
195
|
-
this.#retirementHolds += 1;
|
|
196
|
-
let released = false;
|
|
197
|
-
return () => {
|
|
198
|
-
if (released)
|
|
199
|
-
return;
|
|
200
|
-
released = true;
|
|
201
|
-
this.#retirementHolds -= 1;
|
|
202
|
-
this.#reconcile();
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
setDemand(serverConnectionId, attachmentId, attached) {
|
|
206
|
-
if (this.#retiring)
|
|
207
|
-
throw new Error("Session worker is retiring");
|
|
208
|
-
if (serverConnectionId !== this.#currentServerConnectionId) {
|
|
209
|
-
throw new Error("Session worker received demand from a stale server generation");
|
|
210
|
-
}
|
|
211
|
-
this.#demandInitialized = true;
|
|
212
|
-
if (this.#initialTimer) {
|
|
213
|
-
clearTimeout(this.#initialTimer);
|
|
214
|
-
this.#initialTimer = undefined;
|
|
215
|
-
}
|
|
216
|
-
const key = demandKey(serverConnectionId, attachmentId);
|
|
217
|
-
const previous = this.#demands.get(key);
|
|
218
|
-
if (previous?.timer)
|
|
219
|
-
clearTimeout(previous.timer);
|
|
220
|
-
if (attached)
|
|
221
|
-
this.#demands.set(key, { serverConnectionId, attachmentId });
|
|
222
|
-
else
|
|
223
|
-
this.#demands.delete(key);
|
|
224
|
-
this.#reconcile();
|
|
225
|
-
}
|
|
226
|
-
operationStarted(kind, lane, operationId) {
|
|
227
|
-
this.#activeOperations.add(`${kind}\0${lane}\0${operationId}`);
|
|
228
|
-
}
|
|
229
|
-
operationStopped(kind, lane, operationId) {
|
|
230
|
-
this.#activeOperations.delete(`${kind}\0${lane}\0${operationId}`);
|
|
231
|
-
this.#reconcile();
|
|
232
|
-
}
|
|
233
|
-
close() {
|
|
234
|
-
if (this.#initialTimer)
|
|
235
|
-
clearTimeout(this.#initialTimer);
|
|
236
|
-
for (const demand of this.#demands.values()) {
|
|
237
|
-
if (demand.timer)
|
|
238
|
-
clearTimeout(demand.timer);
|
|
239
|
-
}
|
|
240
|
-
this.#demands.clear();
|
|
241
|
-
}
|
|
242
|
-
#reconcile() {
|
|
243
|
-
if (this.#retiring ||
|
|
244
|
-
!this.#demandInitialized ||
|
|
245
|
-
this.#retirementHolds !== 0 ||
|
|
246
|
-
this.#activeOperations.size !== 0 ||
|
|
247
|
-
this.#demands.size !== 0) {
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
this.#retiring = true;
|
|
251
|
-
this.#onRetire();
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
const DEFAULT_INITIAL_DEMAND_GRACE_MS = 10_000;
|
|
255
|
-
const DEFAULT_ORPHAN_DEMAND_GRACE_MS = 30_000;
|
|
256
|
-
export const SESSION_WORKER_INITIAL_DEMAND_GRACE_ENV = "__PI_SESSION_WORKER_INITIAL_DEMAND_GRACE_MS";
|
|
257
|
-
export const SESSION_WORKER_ORPHAN_DEMAND_GRACE_ENV = "__PI_SESSION_WORKER_ORPHAN_DEMAND_GRACE_MS";
|
|
258
|
-
const CoordinatorInputSchema = Type.Union([
|
|
259
|
-
Type.Object({
|
|
260
|
-
type: Type.Literal("peer_registered"),
|
|
261
|
-
peerId: Type.String(),
|
|
262
|
-
serverConnectionId: Type.Optional(Type.String()),
|
|
263
|
-
}),
|
|
264
|
-
Type.Object({ type: Type.Literal("server_connected"), serverConnectionId: Type.String() }),
|
|
265
|
-
Type.Object({ type: Type.Literal("server_disconnected"), serverConnectionId: Type.String() }),
|
|
266
|
-
Type.Object({ type: Type.Literal("message"), from: Type.Literal("server"), payload: Type.Unknown() }),
|
|
267
|
-
]);
|
|
268
|
-
let failureControl;
|
|
269
|
-
async function connectControl() {
|
|
270
|
-
const address = process.env[SESSION_WORKER_CONTROL_ADDRESS_ENV];
|
|
271
|
-
const token = process.env[SESSION_WORKER_CONTROL_TOKEN_ENV];
|
|
272
|
-
const encodedSessionKey = process.env[SESSION_WORKER_SESSION_KEY_ENV];
|
|
273
|
-
if (!address || !token || !encodedSessionKey)
|
|
274
|
-
throw new Error("Session worker requires a control address");
|
|
275
|
-
const peerId = process.env[SESSION_WORKER_PEER_ID_ENV];
|
|
276
|
-
if (!peerId)
|
|
277
|
-
throw new Error("Session worker requires a peer ID");
|
|
278
|
-
const socket = createConnection(address);
|
|
279
|
-
await new Promise((resolve, reject) => {
|
|
280
|
-
socket.once("connect", resolve);
|
|
281
|
-
socket.once("error", reject);
|
|
282
|
-
});
|
|
283
|
-
const messages = createJsonLineMessages(socket);
|
|
284
|
-
await writeJsonLine(socket, { type: "register_peer", protocol: COORDINATOR_PROTOCOL_VERSION, peerId });
|
|
285
|
-
const registered = await messages[Symbol.asyncIterator]().next();
|
|
286
|
-
if (registered.done ||
|
|
287
|
-
!Check(CoordinatorInputSchema, registered.value) ||
|
|
288
|
-
registered.value.type !== "peer_registered") {
|
|
289
|
-
throw new Error("Coordinator rejected the session worker registration");
|
|
290
|
-
}
|
|
291
|
-
return {
|
|
292
|
-
...(registered.value.serverConnectionId === undefined
|
|
293
|
-
? {}
|
|
294
|
-
: { initialServerConnectionId: registered.value.serverConnectionId }),
|
|
295
|
-
messages,
|
|
296
|
-
socket,
|
|
297
|
-
send: (event) => writeJsonLine(socket, { type: "send", to: "server", payload: event }),
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
async function readCommands(control, handlers) {
|
|
301
|
-
for await (const value of control.messages) {
|
|
302
|
-
if (!Check(CoordinatorInputSchema, value)) {
|
|
303
|
-
control.socket.destroy(new Error("Coordinator sent an invalid worker message"));
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
const message = value;
|
|
307
|
-
if (message.type === "server_connected") {
|
|
308
|
-
handlers.onServerConnected(message.serverConnectionId);
|
|
309
|
-
continue;
|
|
310
|
-
}
|
|
311
|
-
if (message.type === "server_disconnected") {
|
|
312
|
-
handlers.onServerDisconnected(message.serverConnectionId);
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
if (message.type !== "message" || !Check(SessionWorkerCommandSchema, message.payload))
|
|
316
|
-
continue;
|
|
317
|
-
const command = message.payload;
|
|
318
|
-
if (command.type === "shutdown")
|
|
319
|
-
handlers.onShutdown();
|
|
320
|
-
else if (command.type === "discover_workers")
|
|
321
|
-
handlers.onDiscovery();
|
|
322
|
-
else if (command.type === "session_demand")
|
|
323
|
-
await handlers.onDemand(command);
|
|
324
|
-
else if (command.type === "operation_cancel")
|
|
325
|
-
handlers.onOperationCancel(command);
|
|
326
|
-
else
|
|
327
|
-
handlers.onOperation(command);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
function createJsonLineMessages(socket) {
|
|
331
|
-
const queued = [];
|
|
332
|
-
const waiters = [];
|
|
333
|
-
let buffered = "";
|
|
334
|
-
socket.setEncoding("utf8");
|
|
335
|
-
socket.on("data", (chunk) => {
|
|
336
|
-
buffered += chunk;
|
|
337
|
-
if (Buffer.byteLength(buffered) > MAX_CONTROL_LINE_BYTES) {
|
|
338
|
-
socket.destroy(new Error("Session worker control message is too large"));
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
while (true) {
|
|
342
|
-
const newline = buffered.indexOf("\n");
|
|
343
|
-
if (newline === -1)
|
|
344
|
-
return;
|
|
345
|
-
const line = buffered.slice(0, newline);
|
|
346
|
-
buffered = buffered.slice(newline + 1);
|
|
347
|
-
try {
|
|
348
|
-
const value = JSON.parse(line);
|
|
349
|
-
const waiter = waiters.shift();
|
|
350
|
-
if (waiter)
|
|
351
|
-
waiter(value);
|
|
352
|
-
else
|
|
353
|
-
queued.push(value);
|
|
354
|
-
}
|
|
355
|
-
catch {
|
|
356
|
-
socket.destroy(new Error("Session worker received invalid control JSON"));
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
});
|
|
361
|
-
return {
|
|
362
|
-
[Symbol.asyncIterator]() {
|
|
363
|
-
return {
|
|
364
|
-
next: async () => {
|
|
365
|
-
const value = queued.shift() ?? (await new Promise((resolve) => waiters.push(resolve)));
|
|
366
|
-
return { done: false, value };
|
|
367
|
-
},
|
|
368
|
-
};
|
|
369
|
-
},
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
function writeJsonLine(socket, message) {
|
|
373
|
-
return new Promise((resolve, reject) => {
|
|
374
|
-
socket.write(encodeControlLine(message), (error) => {
|
|
375
|
-
if (error)
|
|
376
|
-
reject(error);
|
|
377
|
-
else
|
|
378
|
-
resolve();
|
|
379
|
-
});
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
function toWorkerServiceUpdate(update) {
|
|
383
|
-
if (!isJsonValue(update))
|
|
384
|
-
throw new Error("Service produced a non-JSON update");
|
|
385
|
-
return parseServiceProviderUpdate(update);
|
|
386
|
-
}
|
|
387
|
-
function demandKey(serverConnectionId, attachmentId) {
|
|
388
|
-
return `${serverConnectionId}\0${attachmentId}`;
|
|
389
|
-
}
|
|
390
|
-
function sameScope(left, right) {
|
|
391
|
-
return left.serverConnectionId === right.serverConnectionId && left.attachmentId === right.attachmentId;
|
|
392
|
-
}
|
|
393
|
-
function lifecycleDelay(name, fallback) {
|
|
394
|
-
const value = process.env[name];
|
|
395
|
-
if (value === undefined)
|
|
396
|
-
return fallback;
|
|
397
|
-
const parsed = Number(value);
|
|
398
|
-
if (!Number.isSafeInteger(parsed) || parsed < 0)
|
|
399
|
-
throw new Error(`${name} must be a non-negative safe integer`);
|
|
400
|
-
return parsed;
|
|
401
|
-
}
|
|
402
|
-
async function closeResources(resources) {
|
|
403
|
-
const errors = [];
|
|
404
|
-
try {
|
|
405
|
-
await resources.services?.dispose();
|
|
406
|
-
}
|
|
407
|
-
catch (error) {
|
|
408
|
-
errors.push(error);
|
|
409
|
-
}
|
|
410
|
-
try {
|
|
411
|
-
if (resources.harness)
|
|
412
|
-
await resources.harness.close(TODO_CONTEXT);
|
|
413
|
-
else
|
|
414
|
-
await resources.session?.close(TODO_CONTEXT);
|
|
415
|
-
}
|
|
416
|
-
catch (error) {
|
|
417
|
-
errors.push(error);
|
|
418
|
-
}
|
|
419
|
-
try {
|
|
420
|
-
await resources.repo.close(TODO_CONTEXT);
|
|
421
|
-
}
|
|
422
|
-
catch (error) {
|
|
423
|
-
errors.push(error);
|
|
424
|
-
}
|
|
425
|
-
try {
|
|
426
|
-
await resources.executionEnv.cleanup(TODO_CONTEXT);
|
|
427
|
-
}
|
|
428
|
-
catch (error) {
|
|
429
|
-
errors.push(error);
|
|
430
|
-
}
|
|
431
|
-
try {
|
|
432
|
-
await resources.releaseOwnership();
|
|
433
|
-
}
|
|
434
|
-
catch (error) {
|
|
435
|
-
errors.push(error);
|
|
436
|
-
}
|
|
437
|
-
if (errors.length === 1)
|
|
438
|
-
throw errors[0];
|
|
439
|
-
if (errors.length > 1)
|
|
440
|
-
throw new AggregateError(errors, "Session worker cleanup failed");
|
|
441
|
-
}
|
|
442
|
-
async function run(options, createHarness) {
|
|
443
|
-
const { sessionDir, metadata } = options;
|
|
444
|
-
const sessionId = metadata.id;
|
|
445
|
-
const control = await connectControl();
|
|
446
|
-
const token = process.env[SESSION_WORKER_CONTROL_TOKEN_ENV];
|
|
447
|
-
const sessionKey = Buffer.from(process.env[SESSION_WORKER_SESSION_KEY_ENV], "base64url").toString();
|
|
448
|
-
failureControl = control;
|
|
449
|
-
const pluginManifestPaths = options.pluginManifestPaths;
|
|
450
|
-
const releaseOwnership = await lockfile.lock(metadata.path, {
|
|
451
|
-
realpath: true,
|
|
452
|
-
stale: 2_000,
|
|
453
|
-
update: 1_000,
|
|
454
|
-
retries: { retries: 320, factor: 1, minTimeout: 25, maxTimeout: 25, maxRetryTime: 8_000 },
|
|
455
|
-
});
|
|
456
|
-
const executionEnv = new NodeExecutionEnv({ cwd: metadata.cwd });
|
|
457
|
-
const repo = new JsonlSessionRepo({ fileSystem: executionEnv, sessionsRoot: sessionDir });
|
|
458
|
-
let session;
|
|
459
|
-
let harness;
|
|
460
|
-
let lane;
|
|
461
|
-
let services;
|
|
462
|
-
try {
|
|
463
|
-
session = await repo.open(metadata, TODO_CONTEXT);
|
|
464
|
-
const runtime = await createHarness(session, options, executionEnv);
|
|
465
|
-
harness = runtime.harness;
|
|
466
|
-
lane = runtime.lane ?? (await harness.lane("main", TODO_CONTEXT));
|
|
467
|
-
services = await createSessionWorkerServices({
|
|
468
|
-
lane,
|
|
469
|
-
modelRuntime: runtime.modelRuntime,
|
|
470
|
-
settingsManager: runtime.settingsManager,
|
|
471
|
-
facetLoader: runtime.facetLoader,
|
|
472
|
-
publish: (scope, subscriptionId, update) => control.send({
|
|
473
|
-
type: "service_update",
|
|
474
|
-
token,
|
|
475
|
-
sessionKey,
|
|
476
|
-
scope,
|
|
477
|
-
subscriptionId,
|
|
478
|
-
update: toWorkerServiceUpdate(update),
|
|
479
|
-
}),
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
catch (error) {
|
|
483
|
-
try {
|
|
484
|
-
await closeResources({ harness, services, session, repo, executionEnv, releaseOwnership });
|
|
485
|
-
}
|
|
486
|
-
catch (cleanupError) {
|
|
487
|
-
throw new AggregateError([error, cleanupError], "Session worker startup and cleanup failed");
|
|
488
|
-
}
|
|
489
|
-
throw error;
|
|
490
|
-
}
|
|
491
|
-
const activeRequests = new Map();
|
|
492
|
-
let lifecycle;
|
|
493
|
-
let removeLifecycleListeners = [];
|
|
494
|
-
let closing;
|
|
495
|
-
const close = () => {
|
|
496
|
-
if (closing)
|
|
497
|
-
return closing;
|
|
498
|
-
lifecycle?.close();
|
|
499
|
-
services.removeSubscriptions(() => true);
|
|
500
|
-
for (const request of activeRequests.values())
|
|
501
|
-
request.cancel(new Error("Session worker is closing"));
|
|
502
|
-
activeRequests.clear();
|
|
503
|
-
for (const remove of removeLifecycleListeners)
|
|
504
|
-
remove();
|
|
505
|
-
removeLifecycleListeners = [];
|
|
506
|
-
closing = closeResources({ harness, services, repo, executionEnv, releaseOwnership });
|
|
507
|
-
return closing;
|
|
508
|
-
};
|
|
509
|
-
const closeAndExit = () => {
|
|
510
|
-
void close().then(() => process.exit(0), (error) => {
|
|
511
|
-
console.error(error);
|
|
512
|
-
process.exit(1);
|
|
513
|
-
});
|
|
514
|
-
};
|
|
515
|
-
lifecycle = new WorkerLifecycle({
|
|
516
|
-
initialServerConnectionId: control.initialServerConnectionId,
|
|
517
|
-
initialDemandGraceMs: lifecycleDelay(SESSION_WORKER_INITIAL_DEMAND_GRACE_ENV, DEFAULT_INITIAL_DEMAND_GRACE_MS),
|
|
518
|
-
orphanDemandGraceMs: lifecycleDelay(SESSION_WORKER_ORPHAN_DEMAND_GRACE_ENV, DEFAULT_ORPHAN_DEMAND_GRACE_MS),
|
|
519
|
-
onRetire: closeAndExit,
|
|
520
|
-
});
|
|
521
|
-
removeLifecycleListeners = [
|
|
522
|
-
harness.events.on("run_start", (event) => lifecycle?.operationStarted("run", event.lane, event.runId)),
|
|
523
|
-
harness.events.on("run_resume", (event) => lifecycle?.operationStarted("run", event.lane, event.runId)),
|
|
524
|
-
harness.events.on("run_suspend", (event) => lifecycle?.operationStopped("run", event.lane, event.runId)),
|
|
525
|
-
harness.events.on("run_end", (event) => lifecycle?.operationStopped("run", event.lane, event.runId)),
|
|
526
|
-
harness.events.on("compaction_start", (event) => lifecycle?.operationStarted("compaction", event.lane, event.runId)),
|
|
527
|
-
harness.events.on("compaction_end", (event) => lifecycle?.operationStopped("compaction", event.lane, event.runId)),
|
|
528
|
-
harness.events.on("navigation_start", (event) => lifecycle?.operationStarted("navigation", event.lane, event.runId)),
|
|
529
|
-
harness.events.on("navigation_end", (event) => lifecycle?.operationStopped("navigation", event.lane, event.runId)),
|
|
530
|
-
harness.events.on("fault", closeAndExit),
|
|
531
|
-
];
|
|
532
|
-
const handleOperation = async (request) => {
|
|
533
|
-
let releaseRequest = () => { };
|
|
534
|
-
const cancellable = withCancel(BACKGROUND_CONTEXT);
|
|
535
|
-
try {
|
|
536
|
-
releaseRequest = lifecycle.beginRequest(request.scope.serverConnectionId, request.scope.attachmentId);
|
|
537
|
-
activeRequests.set(request.requestId, { scope: request.scope, cancel: cancellable.cancel });
|
|
538
|
-
const result = await services.invoke(request.call, request.scope, cancellable.context);
|
|
539
|
-
if (result !== undefined && !isJsonValue(result))
|
|
540
|
-
throw new Error("Service produced a non-JSON result");
|
|
541
|
-
await control.send({
|
|
542
|
-
type: "operation_response",
|
|
543
|
-
token,
|
|
544
|
-
sessionKey,
|
|
545
|
-
response: {
|
|
546
|
-
type: "operation_result",
|
|
547
|
-
requestId: request.requestId,
|
|
548
|
-
scope: request.scope,
|
|
549
|
-
...(result === undefined ? {} : { result }),
|
|
550
|
-
},
|
|
551
|
-
});
|
|
552
|
-
}
|
|
553
|
-
catch (error) {
|
|
554
|
-
let code;
|
|
555
|
-
if (error instanceof RemoteServiceError) {
|
|
556
|
-
code = error.code;
|
|
557
|
-
}
|
|
558
|
-
else if (error instanceof Error && "code" in error) {
|
|
559
|
-
const candidate = error.code;
|
|
560
|
-
if (Check(RemoteServiceErrorCodeSchema, candidate))
|
|
561
|
-
code = candidate;
|
|
562
|
-
}
|
|
563
|
-
await control.send({
|
|
564
|
-
type: "operation_response",
|
|
565
|
-
token,
|
|
566
|
-
sessionKey,
|
|
567
|
-
response: {
|
|
568
|
-
type: "operation_error",
|
|
569
|
-
requestId: request.requestId,
|
|
570
|
-
scope: request.scope,
|
|
571
|
-
...(code === undefined ? {} : { code }),
|
|
572
|
-
message: error instanceof Error ? error.message : String(error),
|
|
573
|
-
},
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
finally {
|
|
577
|
-
if (activeRequests.get(request.requestId)?.cancel === cancellable.cancel) {
|
|
578
|
-
activeRequests.delete(request.requestId);
|
|
579
|
-
}
|
|
580
|
-
releaseRequest();
|
|
581
|
-
}
|
|
582
|
-
};
|
|
583
|
-
let ready = false;
|
|
584
|
-
const announce = () => {
|
|
585
|
-
if (!ready)
|
|
586
|
-
return;
|
|
587
|
-
void control
|
|
588
|
-
.send({
|
|
589
|
-
type: "worker_ready",
|
|
590
|
-
token,
|
|
591
|
-
sessionKey,
|
|
592
|
-
sessionId,
|
|
593
|
-
pid: process.pid,
|
|
594
|
-
metadata,
|
|
595
|
-
pluginManifestPaths: [...pluginManifestPaths],
|
|
596
|
-
})
|
|
597
|
-
.catch(() => closeAndExit());
|
|
598
|
-
};
|
|
599
|
-
void readCommands(control, {
|
|
600
|
-
onShutdown: closeAndExit,
|
|
601
|
-
onDiscovery: announce,
|
|
602
|
-
onDemand: async (command) => {
|
|
603
|
-
const releaseRetirement = lifecycle?.holdRetirement() ?? (() => { });
|
|
604
|
-
try {
|
|
605
|
-
try {
|
|
606
|
-
if (!command.attached) {
|
|
607
|
-
const matches = (scope) => scope.serverConnectionId === command.serverConnectionId &&
|
|
608
|
-
scope.attachmentId === command.attachmentId;
|
|
609
|
-
services.removeSubscriptions(matches);
|
|
610
|
-
}
|
|
611
|
-
lifecycle?.setDemand(command.serverConnectionId, command.attachmentId, command.attached);
|
|
612
|
-
}
|
|
613
|
-
catch (error) {
|
|
614
|
-
await control.send({
|
|
615
|
-
type: "demand_rejected",
|
|
616
|
-
token,
|
|
617
|
-
sessionKey,
|
|
618
|
-
requestId: command.requestId,
|
|
619
|
-
message: error instanceof Error ? error.message : String(error),
|
|
620
|
-
});
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
await control.send({
|
|
624
|
-
type: "demand_applied",
|
|
625
|
-
token,
|
|
626
|
-
sessionKey,
|
|
627
|
-
requestId: command.requestId,
|
|
628
|
-
attachmentId: command.attachmentId,
|
|
629
|
-
attached: command.attached,
|
|
630
|
-
});
|
|
631
|
-
}
|
|
632
|
-
finally {
|
|
633
|
-
releaseRetirement();
|
|
634
|
-
}
|
|
635
|
-
},
|
|
636
|
-
onOperation: (request) => {
|
|
637
|
-
void handleOperation(request).catch(() => closeAndExit());
|
|
638
|
-
},
|
|
639
|
-
onOperationCancel: (command) => {
|
|
640
|
-
const active = activeRequests.get(command.requestId);
|
|
641
|
-
if (active !== undefined && sameScope(active.scope, command.scope)) {
|
|
642
|
-
active.cancel(new DOMException("Service operation cancelled", "AbortError"));
|
|
643
|
-
}
|
|
644
|
-
},
|
|
645
|
-
onServerConnected: (serverConnectionId) => lifecycle?.serverConnected(serverConnectionId),
|
|
646
|
-
onServerDisconnected: (serverConnectionId) => {
|
|
647
|
-
const matches = (scope) => scope.serverConnectionId === serverConnectionId;
|
|
648
|
-
services.removeSubscriptions(matches);
|
|
649
|
-
for (const request of activeRequests.values()) {
|
|
650
|
-
if (matches(request.scope))
|
|
651
|
-
request.cancel(new Error("Server disconnected"));
|
|
652
|
-
}
|
|
653
|
-
lifecycle?.serverDisconnected(serverConnectionId);
|
|
654
|
-
},
|
|
655
|
-
}).catch(() => closeAndExit());
|
|
656
|
-
control.socket.once("close", closeAndExit);
|
|
657
|
-
control.socket.once("error", () => closeAndExit());
|
|
658
|
-
process.once("SIGTERM", closeAndExit);
|
|
659
|
-
process.once("SIGINT", closeAndExit);
|
|
660
|
-
try {
|
|
661
|
-
ready = true;
|
|
662
|
-
await control.send({
|
|
663
|
-
type: "worker_ready",
|
|
664
|
-
token,
|
|
665
|
-
sessionKey,
|
|
666
|
-
sessionId,
|
|
667
|
-
pid: process.pid,
|
|
668
|
-
metadata,
|
|
669
|
-
pluginManifestPaths: [...pluginManifestPaths],
|
|
670
|
-
});
|
|
671
|
-
}
|
|
672
|
-
catch (error) {
|
|
673
|
-
try {
|
|
674
|
-
await close();
|
|
675
|
-
}
|
|
676
|
-
catch (cleanupError) {
|
|
677
|
-
throw new AggregateError([error, cleanupError], "Session worker readiness and cleanup failed");
|
|
678
|
-
}
|
|
679
|
-
throw error;
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
export async function runSessionWorkerWithHarness(args, createHarness) {
|
|
683
|
-
try {
|
|
684
|
-
if (args.length !== 1)
|
|
685
|
-
throw new Error("Session worker requires one options argument");
|
|
686
|
-
let options;
|
|
687
|
-
try {
|
|
688
|
-
options = JSON.parse(args[0]);
|
|
689
|
-
}
|
|
690
|
-
catch (error) {
|
|
691
|
-
throw new Error("Session worker received invalid options", { cause: error });
|
|
692
|
-
}
|
|
693
|
-
if (!Check(SessionWorkerOptionsSchema, options) ||
|
|
694
|
-
!isAbsolute(options.sessionDir) ||
|
|
695
|
-
!isAbsolute(options.metadata.cwd) ||
|
|
696
|
-
!isAbsolute(options.metadata.path) ||
|
|
697
|
-
(options.provider !== undefined && options.model === undefined)) {
|
|
698
|
-
throw new Error("Session worker received invalid options");
|
|
699
|
-
}
|
|
700
|
-
await run(options, createHarness);
|
|
701
|
-
}
|
|
702
|
-
catch (error) {
|
|
703
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
704
|
-
const token = process.env[SESSION_WORKER_CONTROL_TOKEN_ENV];
|
|
705
|
-
const encodedSessionKey = process.env[SESSION_WORKER_SESSION_KEY_ENV];
|
|
706
|
-
if (token && encodedSessionKey) {
|
|
707
|
-
const sessionKey = Buffer.from(encodedSessionKey, "base64url").toString();
|
|
708
|
-
await failureControl?.send({ type: "worker_failed", token, sessionKey, message }).catch(() => { });
|
|
709
|
-
}
|
|
710
|
-
throw error;
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
async function createCodingAgentHarness(session, options, executionEnv) {
|
|
714
|
-
const modelRuntime = await ModelRuntime.create();
|
|
715
|
-
const settingsManager = SettingsManager.create(session.metadata.cwd);
|
|
716
|
-
let resolved;
|
|
717
|
-
if (options.model === undefined) {
|
|
718
|
-
resolved = await findInitialModel({
|
|
719
|
-
scopedModels: [],
|
|
720
|
-
isContinuing: true,
|
|
721
|
-
defaultProvider: settingsManager.getDefaultProvider(),
|
|
722
|
-
defaultModelId: settingsManager.getDefaultModel(),
|
|
723
|
-
defaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),
|
|
724
|
-
modelRuntime,
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
else {
|
|
728
|
-
resolved = resolveCliModel({
|
|
729
|
-
cliProvider: options.provider,
|
|
730
|
-
cliModel: options.model,
|
|
731
|
-
modelRuntime,
|
|
732
|
-
});
|
|
733
|
-
if (resolved.error)
|
|
734
|
-
throw new Error(`Session worker could not resolve model: ${resolved.error}`);
|
|
735
|
-
}
|
|
736
|
-
if (!resolved.model)
|
|
737
|
-
throw new Error("Session worker could not resolve a model");
|
|
738
|
-
const tools = [createReadTool(), createWriteTool(), createBashTool()];
|
|
739
|
-
const activeToolNames = tools.map((tool) => tool.name);
|
|
740
|
-
const harness = (await AgentHarness.create({
|
|
741
|
-
session,
|
|
742
|
-
models: modelRuntime,
|
|
743
|
-
model: resolved.model,
|
|
744
|
-
thinkingLevel: resolved.thinkingLevel,
|
|
745
|
-
tools,
|
|
746
|
-
activeToolNames,
|
|
747
|
-
toolContext: { env: executionEnv },
|
|
748
|
-
resources: {},
|
|
749
|
-
}, TODO_CONTEXT)).harness;
|
|
750
|
-
try {
|
|
751
|
-
const lane = await harness.lane("main", TODO_CONTEXT);
|
|
752
|
-
const currentActiveToolNames = await lane.getActiveTools(TODO_CONTEXT);
|
|
753
|
-
if (currentActiveToolNames.length !== activeToolNames.length ||
|
|
754
|
-
currentActiveToolNames.some((name, index) => name !== activeToolNames[index])) {
|
|
755
|
-
await lane.setActiveTools(activeToolNames, TODO_CONTEXT);
|
|
756
|
-
}
|
|
757
|
-
return {
|
|
758
|
-
harness,
|
|
759
|
-
lane,
|
|
760
|
-
modelRuntime,
|
|
761
|
-
settingsManager,
|
|
762
|
-
facetLoader: createSessionPluginFacetLoader(options.pluginManifestPaths),
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
catch (error) {
|
|
766
|
-
try {
|
|
767
|
-
await harness.close(TODO_CONTEXT);
|
|
768
|
-
}
|
|
769
|
-
catch (cleanupError) {
|
|
770
|
-
throw new AggregateError([error, cleanupError], "Session worker model selection and cleanup failed");
|
|
771
|
-
}
|
|
772
|
-
throw error;
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
export function runSessionWorkerProcess(args) {
|
|
776
|
-
return runSessionWorkerWithHarness(args, createCodingAgentHarness);
|
|
777
|
-
}
|
|
778
|
-
if (isDirectInternalProcessEntry(import.meta.url)) {
|
|
779
|
-
const role = consumeInternalProcessRole();
|
|
780
|
-
if (role !== "session-worker") {
|
|
781
|
-
throw new Error("Session worker entrypoint requires an internal session-worker invocation");
|
|
782
|
-
}
|
|
783
|
-
void runSessionWorkerProcess(process.argv.slice(2)).catch(() => process.exit(1));
|
|
784
|
-
}
|
|
785
|
-
//# sourceMappingURL=session-worker.js.map
|