@agimon-ai/po-codemode 0.0.1-alpha.2 → 0.0.1-alpha.21
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/README.md +23 -11
- package/dist/codemodeTools-De6GNjzR.mjs +761 -0
- package/dist/codemodeTools-De6GNjzR.mjs.map +1 -0
- package/dist/codemodeTools-DiqyGxSU.cjs +772 -0
- package/dist/codemodeTools-DiqyGxSU.cjs.map +1 -0
- package/dist/extensions/native.mjs +419 -0
- package/dist/extensions/native.mjs.map +1 -0
- package/dist/extensions/server.cjs +484 -23
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.d.mts.map +1 -1
- package/dist/extensions/server.mjs +485 -24
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/extensions/web.mjs +214 -117
- package/dist/extensions/web.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.mts +24 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/llms.txt +3 -1
- package/package.json +39 -12
- package/src/prompts/codemode-how-to-llm/SKILL.md +29 -0
- package/src/prompts/codemode-how-to-shell/SKILL.md +21 -0
- package/src/prompts/how-to-codemode/SKILL.md +71 -0
- package/dist/codemodeTools-BdwOARH8.mjs +0 -383
- package/dist/codemodeTools-BdwOARH8.mjs.map +0 -1
- package/dist/codemodeTools-CLgSDqfU.cjs +0 -394
- package/dist/codemodeTools-CLgSDqfU.cjs.map +0 -1
- package/src/prompts/po-use-codemode/SKILL.md +0 -46
|
@@ -2,12 +2,19 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_codemodeTools = require("../codemodeTools-
|
|
5
|
+
const require_codemodeTools = require("../codemodeTools-DiqyGxSU.cjs");
|
|
6
6
|
let _agimon_ai_po_core_codemode = require("@agimon-ai/po-core/codemode");
|
|
7
|
+
let _agimon_ai_po_core_approval = require("@agimon-ai/po-core/approval");
|
|
8
|
+
let _agimon_ai_po_core_headless = require("@agimon-ai/po-core/headless");
|
|
9
|
+
let typebox = require("typebox");
|
|
7
10
|
let _agimon_ai_po_core_serverPlugin = require("@agimon-ai/po-core/serverPlugin");
|
|
8
11
|
let _agimon_ai_po_core_extensionFile = require("@agimon-ai/po-core/extensionFile");
|
|
12
|
+
let _agimon_ai_po_config = require("@agimon-ai/po-config");
|
|
13
|
+
let _agimon_ai_po_core_backgroundWork = require("@agimon-ai/po-core/backgroundWork");
|
|
9
14
|
let _agimon_ai_po_core_platform = require("@agimon-ai/po-core/platform");
|
|
10
|
-
let
|
|
15
|
+
let _agimon_ai_po_config_majorModes = require("@agimon-ai/po-config/majorModes");
|
|
16
|
+
let typebox_value = require("typebox/value");
|
|
17
|
+
let typebox_schema = require("typebox/schema");
|
|
11
18
|
//#region src/services/codemodeScripts/index.ts
|
|
12
19
|
const SESSION_FOLDER = "codemode";
|
|
13
20
|
const SESSION_PREFIX = "session:";
|
|
@@ -96,10 +103,13 @@ var FileSystemCodemodeScriptsService = class {
|
|
|
96
103
|
const fs = this.options.fs();
|
|
97
104
|
if (!fs) return [];
|
|
98
105
|
const found = [];
|
|
99
|
-
for (const source of this.sources(domains))
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
for (const source of this.sources(domains)) {
|
|
107
|
+
const names = await this.names(fs, source.directory).catch(() => []);
|
|
108
|
+
for (const name of names) found.push({
|
|
109
|
+
specifier: `${source.domain}/${name.slice(0, -3)}`,
|
|
110
|
+
path: `${source.directory}/${name}`
|
|
111
|
+
});
|
|
112
|
+
}
|
|
103
113
|
const session = this.sessionDirectory();
|
|
104
114
|
if (session !== void 0) for (const name of (await this.names(fs, session)).reverse()) found.push({
|
|
105
115
|
specifier: `${SESSION_PREFIX}${name.slice(0, -3)}`,
|
|
@@ -117,10 +127,378 @@ var FileSystemCodemodeScriptsService = class {
|
|
|
117
127
|
}
|
|
118
128
|
};
|
|
119
129
|
//#endregion
|
|
130
|
+
//#region src/schemas/packageConfig.ts
|
|
131
|
+
const CODEMODE_PACKAGE = "@agimon-ai/po-codemode";
|
|
132
|
+
const CodemodePackageConfigSchema = typebox.Type.Object({ llmModel: typebox.Type.Optional(typebox.Type.String({
|
|
133
|
+
pattern: "^[^/\\s]+/\\S+$",
|
|
134
|
+
maxLength: 256
|
|
135
|
+
})) }, { additionalProperties: false });
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/services/llmConfig/index.ts
|
|
138
|
+
const PO_CODEMODE_LLM_CONFIG_SERVICE = "po/codemode-llm-config";
|
|
139
|
+
/** Session policy is loaded once per immutable Po config snapshot, including failed loads. */
|
|
140
|
+
var LlmConfigService = class {
|
|
141
|
+
io;
|
|
142
|
+
snapshot;
|
|
143
|
+
loads = /* @__PURE__ */ new WeakMap();
|
|
144
|
+
constructor(io) {
|
|
145
|
+
this.io = io;
|
|
146
|
+
}
|
|
147
|
+
bind(snapshot) {
|
|
148
|
+
this.snapshot = snapshot;
|
|
149
|
+
return () => {
|
|
150
|
+
if (this.snapshot === snapshot) this.snapshot = void 0;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
current() {
|
|
154
|
+
if (!this.snapshot) return Promise.resolve({});
|
|
155
|
+
const snapshot = this.snapshot();
|
|
156
|
+
let load = this.loads.get(snapshot);
|
|
157
|
+
if (!load) {
|
|
158
|
+
load = this.load(snapshot);
|
|
159
|
+
this.loads.set(snapshot, load);
|
|
160
|
+
}
|
|
161
|
+
return load;
|
|
162
|
+
}
|
|
163
|
+
async load(snapshot) {
|
|
164
|
+
if (!snapshot.harness.root) return {};
|
|
165
|
+
const { environment, homeDirectory } = this.io;
|
|
166
|
+
const fs = this.io.fs();
|
|
167
|
+
if (!fs || !homeDirectory) throw new Error("Code mode LLM configuration requires host filesystem and home.");
|
|
168
|
+
const modes = await (0, _agimon_ai_po_config_majorModes.readMajorModesConfig)(fs, snapshot.harness.root, _agimon_ai_po_core_platform.BACKGROUND_CONTEXT, {
|
|
169
|
+
environment,
|
|
170
|
+
homeDirectory
|
|
171
|
+
});
|
|
172
|
+
const configurations = await (0, _agimon_ai_po_config_majorModes.readPackageConfigurations)(fs, modes, [...snapshot.harness.layers], CODEMODE_PACKAGE, _agimon_ai_po_core_platform.BACKGROUND_CONTEXT);
|
|
173
|
+
let merged = {};
|
|
174
|
+
for (const entry of configurations) {
|
|
175
|
+
if (!(0, typebox_value.Check)(CodemodePackageConfigSchema, entry.config)) throw new TypeError("Invalid code mode package configuration: llmModel must be provider/modelId.");
|
|
176
|
+
merged = {
|
|
177
|
+
...merged,
|
|
178
|
+
...entry.config
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return merged;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/services/llmNamespace/index.ts
|
|
186
|
+
const MAX_INPUT_BYTES = 65536;
|
|
187
|
+
const MAX_SCHEMA_BYTES = 16384;
|
|
188
|
+
const MAX_OUTPUT_BYTES = 65536;
|
|
189
|
+
const MAX_CALLS = 8;
|
|
190
|
+
const MAX_CONCURRENT = 2;
|
|
191
|
+
const DEFAULT_TOKENS = 1024;
|
|
192
|
+
const MAX_TOKENS = 4096;
|
|
193
|
+
const RESULT_TOOL = "return_result";
|
|
194
|
+
const MODEL = /^[^/\s]+\/\S+$/u;
|
|
195
|
+
const META = typebox_schema.Meta["http://json-schema.org/draft-07/schema#"];
|
|
196
|
+
const DECLARATIONS$1 = `interface LlmRequest {
|
|
197
|
+
prompt: string;
|
|
198
|
+
/** Explicit JSON input only, never the surrounding conversation. */
|
|
199
|
+
input?: unknown;
|
|
200
|
+
system?: string;
|
|
201
|
+
/** provider/modelId; overrides llmModel config and the live session model. */
|
|
202
|
+
model?: string;
|
|
203
|
+
/** Defaults to 1024, maximum 4096. */
|
|
204
|
+
maxTokens?: number;
|
|
205
|
+
}
|
|
206
|
+
declare const llm: {
|
|
207
|
+
/** One-shot text transform. At most 8 calls per exec, 2 concurrently. */
|
|
208
|
+
complete(request: LlmRequest): Promise<{ text: string; model: string }>;
|
|
209
|
+
/** Object-root JSON Schema (draft 7), local nonrecursive refs only. Invalid output rejects without retry. */
|
|
210
|
+
json(request: LlmRequest & { schema: Record<string, unknown> }): Promise<{ value: unknown; model: string }>;
|
|
211
|
+
};`;
|
|
212
|
+
function jsonText(value, limit, label) {
|
|
213
|
+
const json = JSON.stringify(value, (_key, item) => {
|
|
214
|
+
if (item === void 0 || typeof item === "function" || typeof item === "symbol" || typeof item === "bigint" || typeof item === "number" && !Number.isFinite(item)) throw new TypeError(`${label} must be JSON serializable.`);
|
|
215
|
+
return item;
|
|
216
|
+
});
|
|
217
|
+
if (json === void 0) throw new TypeError(`${label} must be JSON serializable.`);
|
|
218
|
+
if (new TextEncoder().encode(json).length > limit) throw new RangeError(`${label} exceeds ${limit} bytes.`);
|
|
219
|
+
return json;
|
|
220
|
+
}
|
|
221
|
+
function object(value) {
|
|
222
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
223
|
+
}
|
|
224
|
+
/** Reject unsupported references and recursive schemas before spending tokens or entering the validator. */
|
|
225
|
+
function checkedSchema(value) {
|
|
226
|
+
const schema = JSON.parse(jsonText(value, MAX_SCHEMA_BYTES, "LLM schema"));
|
|
227
|
+
if (!object(schema) || schema.type !== "object") throw new TypeError("LLM schema must have type: object.");
|
|
228
|
+
if (schema.$schema !== void 0 && schema.$schema !== "http://json-schema.org/draft-07/schema#") throw new TypeError("LLM schema supports JSON Schema draft 7 only.");
|
|
229
|
+
if (!(0, typebox_schema.Check)(META, schema)) throw new TypeError("Invalid LLM JSON Schema.");
|
|
230
|
+
let expanded = 0;
|
|
231
|
+
const visit = (node, ancestors) => {
|
|
232
|
+
if (!object(node)) return;
|
|
233
|
+
if (++expanded > 1024) throw new TypeError("LLM schema exceeds 1024 expanded schema nodes.");
|
|
234
|
+
if (ancestors.length > 32 || ancestors.includes(node)) throw new TypeError("LLM schema references must be nonrecursive and at most 32 levels deep.");
|
|
235
|
+
const stack = [...ancestors, node];
|
|
236
|
+
if (node.$dynamicRef !== void 0 || node.$recursiveRef !== void 0 || node.$id !== void 0) throw new TypeError("LLM schema supports local $ref only, without $id.");
|
|
237
|
+
if (node.$ref !== void 0) {
|
|
238
|
+
if (typeof node.$ref !== "string" || !node.$ref.startsWith("#/")) throw new TypeError("LLM schema supports local JSON-pointer $ref only.");
|
|
239
|
+
let resolved = schema;
|
|
240
|
+
for (const segment of node.$ref.slice(2).split("/")) {
|
|
241
|
+
const key = segment.replace(/~1/gu, "/").replace(/~0/gu, "~");
|
|
242
|
+
resolved = resolved !== null && typeof resolved === "object" && Object.hasOwn(resolved, key) ? Reflect.get(resolved, key) : void 0;
|
|
243
|
+
}
|
|
244
|
+
if (!object(resolved) && typeof resolved !== "boolean") throw new TypeError("Unresolved LLM schema $ref.");
|
|
245
|
+
visit(resolved, stack);
|
|
246
|
+
}
|
|
247
|
+
for (const key of [
|
|
248
|
+
"properties",
|
|
249
|
+
"patternProperties",
|
|
250
|
+
"definitions",
|
|
251
|
+
"$defs",
|
|
252
|
+
"dependencies"
|
|
253
|
+
]) if (object(node[key])) for (const child of Object.values(node[key])) visit(child, stack);
|
|
254
|
+
for (const key of [
|
|
255
|
+
"items",
|
|
256
|
+
"additionalItems",
|
|
257
|
+
"additionalProperties",
|
|
258
|
+
"contains",
|
|
259
|
+
"propertyNames",
|
|
260
|
+
"not",
|
|
261
|
+
"if",
|
|
262
|
+
"then",
|
|
263
|
+
"else",
|
|
264
|
+
"allOf",
|
|
265
|
+
"anyOf",
|
|
266
|
+
"oneOf"
|
|
267
|
+
]) {
|
|
268
|
+
const child = node[key];
|
|
269
|
+
if (Array.isArray(child)) for (const item of child) visit(item, stack);
|
|
270
|
+
else visit(child, stack);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
visit(schema, []);
|
|
274
|
+
return schema;
|
|
275
|
+
}
|
|
276
|
+
function request$1(value, structured) {
|
|
277
|
+
if (!object(value)) throw new TypeError("LLM request must be an object.");
|
|
278
|
+
const allowed = [
|
|
279
|
+
"prompt",
|
|
280
|
+
"input",
|
|
281
|
+
"system",
|
|
282
|
+
"model",
|
|
283
|
+
"maxTokens",
|
|
284
|
+
...structured ? ["schema"] : []
|
|
285
|
+
];
|
|
286
|
+
if (Object.keys(value).some((key) => !allowed.includes(key))) throw new TypeError("Unknown LLM request field.");
|
|
287
|
+
if (typeof value.prompt !== "string" || !value.prompt.trim()) throw new TypeError("LLM prompt must be nonempty text.");
|
|
288
|
+
if (value.system !== void 0 && typeof value.system !== "string") throw new TypeError("LLM system must be text.");
|
|
289
|
+
if (value.model !== void 0 && (typeof value.model !== "string" || !MODEL.test(value.model) || value.model.length > 256)) throw new TypeError("LLM model must be provider/modelId.");
|
|
290
|
+
if (value.maxTokens !== void 0 && (!Number.isInteger(value.maxTokens) || Number(value.maxTokens) < 1 || Number(value.maxTokens) > MAX_TOKENS)) throw new RangeError(`LLM maxTokens must be an integer from 1 to ${MAX_TOKENS}.`);
|
|
291
|
+
return {
|
|
292
|
+
prompt: value.prompt,
|
|
293
|
+
...value.input === void 0 ? {} : { input: value.input },
|
|
294
|
+
...value.system === void 0 ? {} : { system: value.system },
|
|
295
|
+
...value.model === void 0 ? {} : { model: value.model },
|
|
296
|
+
...value.maxTokens === void 0 ? {} : { maxTokens: value.maxTokens },
|
|
297
|
+
...structured ? { schema: checkedSchema(value.schema) } : {}
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
/** Explicit data transforms over the host's guarded completions, never a tool-using agent. */
|
|
301
|
+
function createLlmNamespace(options) {
|
|
302
|
+
const { context } = options;
|
|
303
|
+
return {
|
|
304
|
+
name: "llm",
|
|
305
|
+
summary: "One-shot LLM text and schema-validated JSON transforms. Explicit input only, bounded calls, no tools or retries.",
|
|
306
|
+
declarations: DECLARATIONS$1,
|
|
307
|
+
portable: true,
|
|
308
|
+
bind(run) {
|
|
309
|
+
if (run.sessionId !== context.sessionId) throw new Error("LLM namespace belongs to another session.");
|
|
310
|
+
let disposed = false;
|
|
311
|
+
let calls = 0;
|
|
312
|
+
let active = 0;
|
|
313
|
+
run.onDispose(() => {
|
|
314
|
+
disposed = true;
|
|
315
|
+
});
|
|
316
|
+
const available = () => {
|
|
317
|
+
run.signal.throwIfAborted();
|
|
318
|
+
if (disposed) throw new Error("LLM namespace run is disposed.");
|
|
319
|
+
};
|
|
320
|
+
const call = async (input, structured) => {
|
|
321
|
+
available();
|
|
322
|
+
if (calls >= MAX_CALLS) throw new RangeError(`At most ${MAX_CALLS} LLM calls per exec.`);
|
|
323
|
+
if (active >= MAX_CONCURRENT) throw new RangeError(`At most ${MAX_CONCURRENT} concurrent LLM calls per exec.`);
|
|
324
|
+
const params = request$1(input, structured);
|
|
325
|
+
const userInput = params.input === void 0 ? params.prompt : `${params.prompt}\n\nInput (JSON):\n${jsonText(params.input, MAX_INPUT_BYTES, "LLM input")}`;
|
|
326
|
+
const systemPrompt = `${params.system ?? "Transform only the explicit input according to the request."}${structured ? "\nCall return_result exactly once with the result. Do not call other tools." : ""}`;
|
|
327
|
+
if (new TextEncoder().encode(systemPrompt + userInput).length > MAX_INPUT_BYTES) throw new RangeError("LLM prompt and input exceed 65536 bytes.");
|
|
328
|
+
active += 1;
|
|
329
|
+
const started = Date.now();
|
|
330
|
+
let model;
|
|
331
|
+
let tokens;
|
|
332
|
+
const record = (ok, error) => run.record?.({
|
|
333
|
+
name: structured ? "llm.json" : "llm.complete",
|
|
334
|
+
tool: "llm",
|
|
335
|
+
args: {
|
|
336
|
+
...model ? { model } : {},
|
|
337
|
+
maxTokens: params.maxTokens ?? DEFAULT_TOKENS
|
|
338
|
+
},
|
|
339
|
+
ok,
|
|
340
|
+
ms: Date.now() - started,
|
|
341
|
+
...error === void 0 ? {} : { error },
|
|
342
|
+
...tokens === void 0 ? {} : { result: {
|
|
343
|
+
content: [],
|
|
344
|
+
details: { totalTokens: tokens }
|
|
345
|
+
} }
|
|
346
|
+
});
|
|
347
|
+
try {
|
|
348
|
+
const config = await options.config();
|
|
349
|
+
const current = params.model || config.llmModel ? void 0 : (await context.session.readModelSettings?.())?.model ?? context.model;
|
|
350
|
+
model = params.model ?? config.llmModel ?? (current ? `${current.provider}/${current.id}` : void 0);
|
|
351
|
+
available();
|
|
352
|
+
if (!model || !context.textCompletion?.available(model)) throw new Error(`LLM model is unavailable${model ? `: ${model}` : ""}.`);
|
|
353
|
+
if (structured ? !context.toolCompletion : !context.textCompletion) throw new Error("LLM completion is unavailable on this host.");
|
|
354
|
+
if (calls >= MAX_CALLS) throw new RangeError(`At most ${MAX_CALLS} LLM calls per exec.`);
|
|
355
|
+
calls += 1;
|
|
356
|
+
const completion = {
|
|
357
|
+
systemPrompt,
|
|
358
|
+
input: userInput,
|
|
359
|
+
maxTokens: params.maxTokens ?? DEFAULT_TOKENS,
|
|
360
|
+
signal: run.signal,
|
|
361
|
+
recordUsage: true
|
|
362
|
+
};
|
|
363
|
+
if (!structured) {
|
|
364
|
+
const text = await context.textCompletion.complete(model, completion);
|
|
365
|
+
available();
|
|
366
|
+
jsonText(text, MAX_OUTPUT_BYTES, "LLM output");
|
|
367
|
+
record(true);
|
|
368
|
+
return {
|
|
369
|
+
text,
|
|
370
|
+
model
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
const schema = params.schema;
|
|
374
|
+
const response = await context.toolCompletion.complete(model, {
|
|
375
|
+
...completion,
|
|
376
|
+
tools: [{
|
|
377
|
+
name: RESULT_TOOL,
|
|
378
|
+
description: "Return the requested structured result.",
|
|
379
|
+
parameters: schema
|
|
380
|
+
}]
|
|
381
|
+
});
|
|
382
|
+
tokens = response.usage.totalTokens;
|
|
383
|
+
available();
|
|
384
|
+
if (response.toolCalls.length !== 1 || response.toolCalls[0]?.name !== RESULT_TOOL) throw new Error("LLM must return exactly one return_result call.");
|
|
385
|
+
const value = JSON.parse(jsonText(response.toolCalls[0].arguments, MAX_OUTPUT_BYTES, "LLM output"));
|
|
386
|
+
if (!(0, typebox_schema.Check)(schema, value)) {
|
|
387
|
+
const [, errors] = (0, typebox_schema.Errors)(schema, value);
|
|
388
|
+
throw new TypeError(`LLM result failed schema validation: ${errors[0]?.message ?? "invalid result"}`);
|
|
389
|
+
}
|
|
390
|
+
record(true);
|
|
391
|
+
return {
|
|
392
|
+
value,
|
|
393
|
+
model
|
|
394
|
+
};
|
|
395
|
+
} catch (error) {
|
|
396
|
+
record(false, error instanceof Error ? error.message : String(error));
|
|
397
|
+
throw error;
|
|
398
|
+
} finally {
|
|
399
|
+
active -= 1;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
return {
|
|
403
|
+
complete: (input) => call(input, false),
|
|
404
|
+
json: (input) => call(input, true)
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
//#endregion
|
|
410
|
+
//#region src/services/shellNamespace/index.ts
|
|
411
|
+
const DEFAULT_TIMEOUT_MS = 1e4;
|
|
412
|
+
const MAX_TIMEOUT_MS = 12e4;
|
|
413
|
+
const MAX_COMMAND_CHARS = 65536;
|
|
414
|
+
const MAX_OUTPUT_CHARS = 32768;
|
|
415
|
+
const TRUNCATED = "\n[truncated]";
|
|
416
|
+
const DECLARATIONS = `declare const shell: {
|
|
417
|
+
/** Short foreground Bash command in the session cwd/environment. Nonzero exits are returned; cancellation and timeout reject. */
|
|
418
|
+
bash(input: { command: string; timeoutMs?: number }): Promise<{ stdout: string; stderr: string; exitCode: number }>;
|
|
419
|
+
};`;
|
|
420
|
+
function request(input) {
|
|
421
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) throw new TypeError("shell.bash expects an object.");
|
|
422
|
+
const value = input;
|
|
423
|
+
if (Object.keys(value).some((key) => key !== "command" && key !== "timeoutMs")) throw new TypeError("shell.bash accepts only command and timeoutMs.");
|
|
424
|
+
if (typeof value.command !== "string" || !value.command.trim() || value.command.length > MAX_COMMAND_CHARS) throw new TypeError(`shell.bash command must be nonempty text of at most ${MAX_COMMAND_CHARS} characters.`);
|
|
425
|
+
if (value.timeoutMs !== void 0 && (!Number.isInteger(value.timeoutMs) || Number(value.timeoutMs) < 1 || Number(value.timeoutMs) > MAX_TIMEOUT_MS)) throw new RangeError(`shell.bash timeoutMs must be an integer from 1 to ${MAX_TIMEOUT_MS}.`);
|
|
426
|
+
return {
|
|
427
|
+
command: value.command,
|
|
428
|
+
timeoutMs: value.timeoutMs
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
/** Deadline-bound commands for post-processing, separate from Runner's supervised processes. */
|
|
432
|
+
function createShellNamespace(options) {
|
|
433
|
+
return {
|
|
434
|
+
name: "shell",
|
|
435
|
+
summary: "Run short foreground Bash commands with bounded stdout/stderr and a deadline. No background or interactive mode.",
|
|
436
|
+
declarations: DECLARATIONS,
|
|
437
|
+
portable: true,
|
|
438
|
+
bind(run) {
|
|
439
|
+
if (run.sessionId !== options.context.sessionId) throw new Error("Shell namespace belongs to another session.");
|
|
440
|
+
const disposal = new AbortController();
|
|
441
|
+
const lifetime = AbortSignal.any([run.signal, disposal.signal]);
|
|
442
|
+
run.onDispose(() => disposal.abort(/* @__PURE__ */ new Error("Shell namespace run is disposed.")));
|
|
443
|
+
return { async bash(input) {
|
|
444
|
+
lifetime.throwIfAborted();
|
|
445
|
+
const params = request(input);
|
|
446
|
+
const shell = options.shell();
|
|
447
|
+
if (!shell) throw new Error("Shell commands are not available on this host.");
|
|
448
|
+
const timeoutMs = params.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
449
|
+
const signal = AbortSignal.any([lifetime, AbortSignal.timeout(timeoutMs)]);
|
|
450
|
+
const output = {
|
|
451
|
+
stdout: "",
|
|
452
|
+
stderr: ""
|
|
453
|
+
};
|
|
454
|
+
const truncated = {
|
|
455
|
+
stdout: false,
|
|
456
|
+
stderr: false
|
|
457
|
+
};
|
|
458
|
+
const started = Date.now();
|
|
459
|
+
let ok = false;
|
|
460
|
+
let failure;
|
|
461
|
+
try {
|
|
462
|
+
const result = await shell.exec(params.command, {
|
|
463
|
+
cwd: options.context.cwd,
|
|
464
|
+
env: Object.fromEntries(Object.entries(options.context.environment).filter((entry) => entry[1] !== void 0)),
|
|
465
|
+
inheritEnv: false,
|
|
466
|
+
onOutput: (text, _context, { stream }) => {
|
|
467
|
+
const remaining = MAX_OUTPUT_CHARS - output[stream].length;
|
|
468
|
+
output[stream] += text.slice(0, remaining);
|
|
469
|
+
if (text.length > remaining) truncated[stream] = true;
|
|
470
|
+
}
|
|
471
|
+
}, (0, _agimon_ai_po_core_platform.withAbortSignal)(signal, _agimon_ai_po_core_platform.BACKGROUND_CONTEXT));
|
|
472
|
+
signal.throwIfAborted();
|
|
473
|
+
const { exitCode } = (0, _agimon_ai_po_core_platform.getOrThrow)(result);
|
|
474
|
+
ok = exitCode === 0;
|
|
475
|
+
return {
|
|
476
|
+
stdout: output.stdout + (truncated.stdout ? TRUNCATED : ""),
|
|
477
|
+
stderr: output.stderr + (truncated.stderr ? TRUNCATED : ""),
|
|
478
|
+
exitCode
|
|
479
|
+
};
|
|
480
|
+
} catch (error) {
|
|
481
|
+
failure = error instanceof Error ? error.message : String(error);
|
|
482
|
+
throw error;
|
|
483
|
+
} finally {
|
|
484
|
+
run.record?.({
|
|
485
|
+
name: "shell.bash",
|
|
486
|
+
tool: "shell",
|
|
487
|
+
args: { timeoutMs },
|
|
488
|
+
ok,
|
|
489
|
+
ms: Date.now() - started,
|
|
490
|
+
...failure === void 0 ? {} : { error: failure }
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
} };
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
//#endregion
|
|
120
498
|
//#region src/extensions/workspaces/sessions/(backend)/_lib/root.server.ts
|
|
121
499
|
/** One registry per session: contributors register into it, `discover` and `exec` read it. */
|
|
122
|
-
function createCodemodeSession({ context }) {
|
|
123
|
-
const registry = require_codemodeTools.createCodemodeRegistry();
|
|
500
|
+
function createCodemodeSession({ context, agent, host, signal }) {
|
|
501
|
+
const registry = require_codemodeTools.createCodemodeRegistry({ isActive: (source) => (0, _agimon_ai_po_core_headless.readPoHeadlessHost)(context)?.isSourceActive(source) ?? true });
|
|
124
502
|
context.inject([_agimon_ai_po_core_serverPlugin.PO_SERVER_SCOPE_SERVICE], (scoped) => (0, _agimon_ai_po_core_serverPlugin.requirePoServerScope)(scoped).provide(_agimon_ai_po_core_codemode.PO_CODEMODE_CONTRACT, registry));
|
|
125
503
|
let temporaryDirectory;
|
|
126
504
|
context.inject([_agimon_ai_po_core_platform.PO_SESSION_FILES_SERVICE], (scoped) => {
|
|
@@ -134,14 +512,62 @@ function createCodemodeSession({ context }) {
|
|
|
134
512
|
fs: () => (0, _agimon_ai_po_core_platform.readPoFs)(context),
|
|
135
513
|
temporaryDirectory: () => temporaryDirectory
|
|
136
514
|
});
|
|
137
|
-
|
|
515
|
+
const execution = agent?.context;
|
|
516
|
+
const config = execution ? new LlmConfigService({
|
|
517
|
+
fs: () => (0, _agimon_ai_po_core_platform.readPoFs)(context),
|
|
518
|
+
environment: execution.environment,
|
|
519
|
+
homeDirectory: host.context.homeDirectory
|
|
520
|
+
}) : void 0;
|
|
521
|
+
let disposeNamespaces;
|
|
522
|
+
if (execution && config) {
|
|
523
|
+
context.inject([_agimon_ai_po_config.PO_CONFIG_SERVICE], (scoped) => {
|
|
524
|
+
const service = scoped.get(_agimon_ai_po_config.PO_CONFIG_SERVICE);
|
|
525
|
+
return service ? config.bind(() => service.getSnapshot()) : void 0;
|
|
526
|
+
});
|
|
527
|
+
const registration = registry.register("@agimon-ai/po-codemode", createLlmNamespace({
|
|
528
|
+
context: execution,
|
|
529
|
+
config: () => config.current()
|
|
530
|
+
}));
|
|
531
|
+
const shellRegistration = registry.register("@agimon-ai/po-codemode", createShellNamespace({
|
|
532
|
+
context: execution,
|
|
533
|
+
shell: () => context.get(_agimon_ai_po_core_platform.PO_SHELL_SERVICE)
|
|
534
|
+
}));
|
|
535
|
+
disposeNamespaces = () => {
|
|
536
|
+
registration.dispose();
|
|
537
|
+
shellRegistration.dispose();
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
let background;
|
|
541
|
+
const tools = require_codemodeTools.createCodemodeTools({
|
|
138
542
|
registry,
|
|
139
|
-
|
|
543
|
+
isolate: () => (0, _agimon_ai_po_core_platform.readPoIsolate)(context),
|
|
544
|
+
npm: () => (0, _agimon_ai_po_core_platform.readPoNpm)(context),
|
|
545
|
+
scripts,
|
|
546
|
+
signal,
|
|
547
|
+
onBackgroundChange: () => background?.update(),
|
|
548
|
+
approval: () => (0, _agimon_ai_po_core_approval.readPoApproval)(context)
|
|
549
|
+
});
|
|
550
|
+
context.inject([_agimon_ai_po_core_backgroundWork.PO_BACKGROUND_WORK_SERVICE], (scoped) => {
|
|
551
|
+
const registration = (0, _agimon_ai_po_core_backgroundWork.readPoBackgroundWorkService)(scoped)?.register(tools.backgroundWork);
|
|
552
|
+
background = registration;
|
|
553
|
+
return () => {
|
|
554
|
+
if (background === registration) background = void 0;
|
|
555
|
+
registration?.dispose();
|
|
556
|
+
};
|
|
557
|
+
});
|
|
558
|
+
return {
|
|
559
|
+
value: {
|
|
140
560
|
registry,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
561
|
+
...tools
|
|
562
|
+
},
|
|
563
|
+
services: [(scoped) => {
|
|
564
|
+
if (config) scoped.provide(PO_CODEMODE_LLM_CONFIG_SERVICE, config);
|
|
565
|
+
}],
|
|
566
|
+
onDispose: async () => {
|
|
567
|
+
await tools.dispose();
|
|
568
|
+
disposeNamespaces?.();
|
|
569
|
+
}
|
|
570
|
+
};
|
|
145
571
|
}
|
|
146
572
|
const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(createCodemodeSession);
|
|
147
573
|
//#endregion
|
|
@@ -151,19 +577,45 @@ var root_server_default = (0, _agimon_ai_po_core_extensionFile.defineRoot)(root)
|
|
|
151
577
|
//#region src/extensions/workspaces/sessions/(backend)/contract/codemode.server.ts
|
|
152
578
|
var codemode_server_default = (0, _agimon_ai_po_core_extensionFile.defineServiceContract)(_agimon_ai_po_core_codemode.PO_CODEMODE_SERVICE, { scope: "session" });
|
|
153
579
|
//#endregion
|
|
154
|
-
//#region src/extensions/workspaces/sessions/(backend)/resource/
|
|
155
|
-
var
|
|
156
|
-
name: "
|
|
157
|
-
description: "
|
|
158
|
-
|
|
580
|
+
//#region src/extensions/workspaces/sessions/(backend)/resource/codemode-how-to-llm.server.ts
|
|
581
|
+
var codemode_how_to_llm_server_default = (0, _agimon_ai_po_core_extensionFile.defineResource)({
|
|
582
|
+
name: "codemode-how-to-llm",
|
|
583
|
+
description: "Have a model classify, extract or summarize data inside a script, with JSON output checked against a schema. Use when a script step needs judgement over many items or messy text; answer directly when no script needs the result.",
|
|
584
|
+
pinned: true,
|
|
159
585
|
kind: "skill",
|
|
160
|
-
path: (0, _agimon_ai_po_core_serverPlugin.packageResourcePath)(require("url").pathToFileURL(__filename).href, "src/prompts/
|
|
161
|
-
read: () => (0, _agimon_ai_po_core_serverPlugin.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/
|
|
586
|
+
path: (0, _agimon_ai_po_core_serverPlugin.packageResourcePath)(require("url").pathToFileURL(__filename).href, "src/prompts/codemode-how-to-llm/SKILL.md"),
|
|
587
|
+
read: () => (0, _agimon_ai_po_core_serverPlugin.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/codemode-how-to-llm/SKILL.md")
|
|
588
|
+
});
|
|
589
|
+
//#endregion
|
|
590
|
+
//#region src/extensions/workspaces/sessions/(backend)/resource/codemode-how-to-shell.server.ts
|
|
591
|
+
var codemode_how_to_shell_server_default = (0, _agimon_ai_po_core_extensionFile.defineResource)({
|
|
592
|
+
name: "codemode-how-to-shell",
|
|
593
|
+
description: "Run a quick command inside a script and work with its output as data. Use when command output needs parsing or filtering in code; use the bash tool for long-running, interactive or visible commands.",
|
|
594
|
+
pinned: true,
|
|
595
|
+
kind: "skill",
|
|
596
|
+
path: (0, _agimon_ai_po_core_serverPlugin.packageResourcePath)(require("url").pathToFileURL(__filename).href, "src/prompts/codemode-how-to-shell/SKILL.md"),
|
|
597
|
+
read: () => (0, _agimon_ai_po_core_serverPlugin.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/codemode-how-to-shell/SKILL.md")
|
|
598
|
+
});
|
|
599
|
+
//#endregion
|
|
600
|
+
//#region src/extensions/workspaces/sessions/(backend)/resource/how-to-codemode.server.ts
|
|
601
|
+
var how_to_codemode_server_default = (0, _agimon_ai_po_core_extensionFile.defineResource)({
|
|
602
|
+
name: "how-to-codemode",
|
|
603
|
+
description: "Do multi-step work in one call: script loops, filtering and chained calls across live namespaces in exec instead of many separate tool calls. Use when a task repeats a tool, combines namespaces, or needs a long-running workflow.",
|
|
604
|
+
pinned: true,
|
|
605
|
+
kind: "skill",
|
|
606
|
+
path: (0, _agimon_ai_po_core_serverPlugin.packageResourcePath)(require("url").pathToFileURL(__filename).href, "src/prompts/how-to-codemode/SKILL.md"),
|
|
607
|
+
read: () => (0, _agimon_ai_po_core_serverPlugin.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/how-to-codemode/SKILL.md")
|
|
162
608
|
});
|
|
163
609
|
//#endregion
|
|
164
610
|
//#region src/extensions/workspaces/sessions/(backend)/tool/discover.server.ts
|
|
165
611
|
var discover_server_default = (0, _agimon_ai_po_core_extensionFile.defineServerTool)((context) => context.root.discover);
|
|
166
612
|
//#endregion
|
|
613
|
+
//#region src/extensions/workspaces/sessions/(backend)/tool/exec_background.server.ts
|
|
614
|
+
var exec_background_server_default = (0, _agimon_ai_po_core_extensionFile.defineServerTool)((context) => context.root.execBackground);
|
|
615
|
+
//#endregion
|
|
616
|
+
//#region src/extensions/workspaces/sessions/(backend)/tool/exec_cancel.server.ts
|
|
617
|
+
var exec_cancel_server_default = (0, _agimon_ai_po_core_extensionFile.defineServerTool)((context) => context.root.execCancel);
|
|
618
|
+
//#endregion
|
|
167
619
|
//#region src/extensions/workspaces/sessions/(backend)/tool/exec.server.ts
|
|
168
620
|
var exec_server_default = (0, _agimon_ai_po_core_extensionFile.defineServerTool)((context) => context.root.exec);
|
|
169
621
|
//#endregion
|
|
@@ -187,10 +639,19 @@ const serverPlugin = (0, _agimon_ai_po_core_serverPlugin.defineServerPlugin)({
|
|
|
187
639
|
return {
|
|
188
640
|
...(0, _agimon_ai_po_core_extensionFile.composeRootHooks)(scopeSession),
|
|
189
641
|
get resources() {
|
|
190
|
-
return [
|
|
642
|
+
return [
|
|
643
|
+
at(codemode_how_to_llm_server_default, contextSession),
|
|
644
|
+
at(codemode_how_to_shell_server_default, contextSession),
|
|
645
|
+
at(how_to_codemode_server_default, contextSession)
|
|
646
|
+
];
|
|
191
647
|
},
|
|
192
648
|
get tools() {
|
|
193
|
-
return [
|
|
649
|
+
return [
|
|
650
|
+
via({ name: "discover" }, at(discover_server_default, contextSession)),
|
|
651
|
+
via({ name: "exec_background" }, at(exec_background_server_default, contextSession)),
|
|
652
|
+
via({ name: "exec_cancel" }, at(exec_cancel_server_default, contextSession)),
|
|
653
|
+
via({ name: "exec" }, at(exec_server_default, contextSession))
|
|
654
|
+
];
|
|
194
655
|
},
|
|
195
656
|
services: [...scopeSession.services ?? []],
|
|
196
657
|
get activities() {
|