@easynet/agent-runtime 1.0.2 → 1.0.4
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/.github/workflows/ci.yml +9 -24
- package/.github/workflows/release.yml +38 -26
- package/agent-runtime/.github/workflows/ci.yml +69 -0
- package/agent-runtime/.github/workflows/release.yml +118 -0
- package/agent-runtime/.releaserc.cjs +26 -0
- package/agent-runtime/config/agent.deep.yaml +25 -0
- package/agent-runtime/config/agent.react.yaml +24 -0
- package/agent-runtime/example/basic-usage.ts +49 -0
- package/agent-runtime/package-lock.json +7740 -0
- package/agent-runtime/package.json +49 -0
- package/agent-runtime/pnpm-lock.yaml +3712 -0
- package/agent-runtime/scripts/resolve-deps.js +54 -0
- package/agent-runtime/src/agents/deep-agent.ts +165 -0
- package/agent-runtime/src/agents/react-agent.helpers.ts +227 -0
- package/agent-runtime/src/agents/react-agent.ts +584 -0
- package/{src → agent-runtime/src/agents}/sub-agent.ts +2 -2
- package/agent-runtime/src/cli/args.ts +15 -0
- package/agent-runtime/src/cli/event-listener.ts +162 -0
- package/agent-runtime/src/cli/interactive.ts +144 -0
- package/agent-runtime/src/cli/runtime.ts +31 -0
- package/agent-runtime/src/cli/spinner.ts +23 -0
- package/agent-runtime/src/cli/terminal-render.ts +322 -0
- package/agent-runtime/src/cli/types.ts +33 -0
- package/agent-runtime/src/cli.ts +134 -0
- package/agent-runtime/src/config/helpers.ts +179 -0
- package/agent-runtime/src/config/index.ts +245 -0
- package/agent-runtime/src/config/types.ts +62 -0
- package/agent-runtime/src/core/context.ts +266 -0
- package/agent-runtime/src/index.ts +55 -0
- package/agent-runtime/tsconfig.json +18 -0
- package/apps/imessagebot/README.md +38 -0
- package/apps/imessagebot/config/.agent/cache/easynet/agent-tool-buildin/0.0.45/README.md +33 -0
- package/apps/imessagebot/config/.agent/cache/easynet/agent-tool-buildin/0.0.45/package-lock.json +15257 -0
- package/apps/imessagebot/config/.agent/cache/easynet/agent-tool-buildin/0.0.45/package.json +55 -0
- package/apps/imessagebot/config/agents/deep/agent.yaml +31 -0
- package/apps/imessagebot/config/agents/react/agent.yaml +58 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.43/README.md +33 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.43/package-lock.json +15457 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.43/package.json +55 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.46/README.md +33 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.46/package-lock.json +15257 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.46/package.json +62 -0
- package/apps/imessagebot/config/agents/shared/memory.yaml +31 -0
- package/apps/imessagebot/config/agents/shared/model.yaml +23 -0
- package/apps/imessagebot/config/agents/shared/tool.yaml +13 -0
- package/apps/imessagebot/config/app.yaml +14 -0
- package/apps/imessagebot/package-lock.json +53695 -0
- package/apps/imessagebot/package.json +41 -0
- package/apps/imessagebot/pnpm-lock.yaml +1589 -0
- package/apps/imessagebot/scripts/resolve-deps.js +41 -0
- package/apps/imessagebot/scripts/test-llm.mjs +27 -0
- package/apps/imessagebot/scripts/validate-tools-config.mjs +174 -0
- package/apps/imessagebot/src/config.ts +76 -0
- package/apps/imessagebot/src/context.ts +35 -0
- package/apps/imessagebot/src/index.ts +17 -0
- package/apps/imessagebot/tsconfig.json +18 -0
- package/apps/itermbot/.github/workflows/ci.yml +61 -0
- package/apps/itermbot/.github/workflows/release.yml +80 -0
- package/apps/itermbot/.releaserc.cjs +26 -0
- package/apps/itermbot/README.md +82 -0
- package/apps/itermbot/config/app.yaml +29 -0
- package/apps/itermbot/config/tsconfig.json +18 -0
- package/apps/itermbot/macos_disk_usage_agent_plan.md +244 -0
- package/apps/itermbot/package-lock.json +53697 -0
- package/apps/itermbot/package.json +57 -0
- package/apps/itermbot/pnpm-lock.yaml +3966 -0
- package/apps/itermbot/scripts/patch-buildin-cache.sh +25 -0
- package/apps/itermbot/scripts/resolve-deps.js +41 -0
- package/apps/itermbot/scripts/test-llm.mjs +32 -0
- package/apps/itermbot/skills/command-explain-and-guard/SKILL.md +39 -0
- package/apps/itermbot/skills/command-explain-and-guard/handler.js +86 -0
- package/apps/itermbot/skills/disk-usage-investigate/SKILL.md +44 -0
- package/apps/itermbot/skills/disk-usage-investigate/handler.js +12 -0
- package/apps/itermbot/skills/gpu-ssh-monitor/SKILL.md +64 -0
- package/apps/itermbot/skills/repo-triage/SKILL.md +40 -0
- package/apps/itermbot/skills/repo-triage/handler.js +56 -0
- package/apps/itermbot/skills/test-failure-diagnose/SKILL.md +43 -0
- package/apps/itermbot/skills/test-failure-diagnose/handler.js +107 -0
- package/apps/itermbot/src/config.ts +95 -0
- package/apps/itermbot/src/context.ts +35 -0
- package/apps/itermbot/src/index.ts +223 -0
- package/apps/itermbot/src/iterm/session-hint.ts +40 -0
- package/apps/itermbot/src/iterm/target-routing.ts +419 -0
- package/apps/itermbot/src/startup/colors.ts +317 -0
- package/apps/itermbot/src/startup/diagnostics.ts +97 -0
- package/apps/itermbot/src/startup/ui.ts +141 -0
- package/config/agent.deep.yaml +25 -0
- package/config/agent.react.yaml +24 -0
- package/dist/agents/deep-agent.d.ts +37 -0
- package/dist/agents/deep-agent.d.ts.map +1 -0
- package/dist/agents/deep-agent.js +115 -0
- package/dist/agents/deep-agent.js.map +1 -0
- package/dist/agents/react-agent.d.ts +40 -0
- package/dist/agents/react-agent.d.ts.map +1 -0
- package/dist/agents/react-agent.helpers.d.ts +40 -0
- package/dist/agents/react-agent.helpers.d.ts.map +1 -0
- package/dist/agents/react-agent.helpers.js +196 -0
- package/dist/agents/react-agent.helpers.js.map +1 -0
- package/dist/agents/react-agent.js +400 -0
- package/dist/agents/react-agent.js.map +1 -0
- package/dist/agents/sub-agent.d.ts +34 -0
- package/dist/agents/sub-agent.d.ts.map +1 -0
- package/dist/agents/sub-agent.js +53 -0
- package/dist/agents/sub-agent.js.map +1 -0
- package/dist/cli/args.d.ts +8 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +9 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/event-listener.d.ts +3 -0
- package/dist/cli/event-listener.d.ts.map +1 -0
- package/dist/cli/event-listener.js +131 -0
- package/dist/cli/event-listener.js.map +1 -0
- package/dist/cli/interactive.d.ts +4 -0
- package/dist/cli/interactive.d.ts.map +1 -0
- package/dist/cli/interactive.js +118 -0
- package/dist/cli/interactive.js.map +1 -0
- package/dist/cli/runtime.d.ts +8 -0
- package/dist/cli/runtime.d.ts.map +1 -0
- package/dist/cli/runtime.js +27 -0
- package/dist/cli/runtime.js.map +1 -0
- package/dist/cli/spinner.d.ts +2 -0
- package/dist/cli/spinner.d.ts.map +1 -0
- package/dist/cli/spinner.js +22 -0
- package/dist/cli/spinner.js.map +1 -0
- package/dist/cli/terminal-render.d.ts +7 -0
- package/dist/cli/terminal-render.d.ts.map +1 -0
- package/dist/cli/terminal-render.js +282 -0
- package/dist/cli/terminal-render.js.map +1 -0
- package/dist/cli/types.d.ts +29 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +3 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli.d.ts +4 -41
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +84 -588
- package/dist/cli.js.map +1 -1
- package/dist/config/helpers.d.ts +6 -0
- package/dist/config/helpers.d.ts.map +1 -0
- package/dist/config/helpers.js +164 -0
- package/dist/config/helpers.js.map +1 -0
- package/dist/config/index.d.ts +15 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +160 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +57 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/context.d.ts +8 -69
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +44 -24
- package/dist/context.js.map +1 -1
- package/dist/core/context.d.ts +66 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +149 -0
- package/dist/core/context.js.map +1 -0
- package/dist/deep-agent.d.ts +5 -2
- package/dist/deep-agent.d.ts.map +1 -1
- package/dist/deep-agent.js +44 -11
- package/dist/deep-agent.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/middleware/malformed-tool-call-middleware.d.ts +8 -0
- package/dist/middleware/malformed-tool-call-middleware.d.ts.map +1 -0
- package/dist/middleware/malformed-tool-call-middleware.js +191 -0
- package/dist/middleware/malformed-tool-call-middleware.js.map +1 -0
- package/dist/react-agent.d.ts +2 -2
- package/dist/react-agent.d.ts.map +1 -1
- package/dist/react-agent.js +28 -9
- package/dist/react-agent.js.map +1 -1
- package/package.json +1 -1
- package/scripts/resolve-deps.js +54 -0
- package/src/agents/deep-agent.ts +165 -0
- package/src/agents/react-agent.helpers.ts +227 -0
- package/src/agents/react-agent.ts +584 -0
- package/src/agents/sub-agent.ts +82 -0
- package/src/cli/args.ts +15 -0
- package/src/cli/event-listener.ts +162 -0
- package/src/cli/interactive.ts +144 -0
- package/src/cli/runtime.ts +31 -0
- package/src/cli/spinner.ts +23 -0
- package/src/cli/terminal-render.ts +322 -0
- package/src/cli/types.ts +33 -0
- package/src/cli.ts +91 -702
- package/src/config/helpers.ts +179 -0
- package/src/config/index.ts +245 -0
- package/src/config/types.ts +62 -0
- package/src/core/context.ts +266 -0
- package/src/index.ts +13 -11
- package/src/middleware/malformed-tool-call-middleware.ts +239 -0
- package/src/types/markdown-it-terminal.d.ts +4 -0
- package/src/types/marked-terminal.d.ts +16 -0
- package/dist/config.d.ts +0 -86
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -84
- package/dist/config.js.map +0 -1
- package/src/config.ts +0 -177
- package/src/context.ts +0 -247
- package/src/deep-agent.ts +0 -104
- package/src/react-agent.ts +0 -576
- /package/{src → agent-runtime/src/middleware}/malformed-tool-call-middleware.ts +0 -0
- /package/{src → agent-runtime/src/types}/markdown-it-terminal.d.ts +0 -0
- /package/{src → agent-runtime/src/types}/marked-terminal.d.ts +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* resolve-deps.js
|
|
4
|
+
*
|
|
5
|
+
* Run automatically via `preinstall` npm hook.
|
|
6
|
+
* In CI (CI=true), rewrites file: references in package.json to npm versions
|
|
7
|
+
* so that `npm install` can resolve them without local sibling directories.
|
|
8
|
+
*
|
|
9
|
+
* Local development: no-op (CI env var is not set).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
13
|
+
import { resolve, dirname } from 'path';
|
|
14
|
+
import { fileURLToPath } from 'url';
|
|
15
|
+
|
|
16
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const pkgPath = resolve(__dirname, '..', 'package.json');
|
|
18
|
+
|
|
19
|
+
if (!process.env.CI) {
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
24
|
+
let changed = false;
|
|
25
|
+
|
|
26
|
+
for (const section of ['dependencies', 'devDependencies']) {
|
|
27
|
+
const deps = pkg[section];
|
|
28
|
+
if (!deps) continue;
|
|
29
|
+
for (const [name, version] of Object.entries(deps)) {
|
|
30
|
+
if (name.startsWith('@easynet/') && typeof version === 'string' && version.startsWith('file:')) {
|
|
31
|
+
deps[name] = 'latest';
|
|
32
|
+
changed = true;
|
|
33
|
+
console.log(`[resolve-deps] ${name}: file: → latest`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (changed) {
|
|
39
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
40
|
+
console.log('[resolve-deps] package.json updated for CI.');
|
|
41
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quick LLM config test. Run from app root: npm run test:llm
|
|
3
|
+
*/
|
|
4
|
+
import { createAgentLlm } from "@easynet/agent-model";
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
try {
|
|
8
|
+
console.log("[test-llm] Loading LLM from config/agents/shared/model.yaml ...");
|
|
9
|
+
const llm = await createAgentLlm({
|
|
10
|
+
configPath: "config/agents/shared/model.yaml",
|
|
11
|
+
checkConnectivity: false,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
console.log("[test-llm] Invoking LLM ...");
|
|
15
|
+
const res = await llm.invoke(
|
|
16
|
+
"In one sentence, introduce yourself and say you are being used to test iMessageBot's LLM config."
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
console.log("[test-llm] Raw response:");
|
|
20
|
+
console.log(JSON.stringify(res, null, 2));
|
|
21
|
+
} catch (err) {
|
|
22
|
+
console.error("[test-llm] Error:", err);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
main();
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve, dirname } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { loadYamlFile } from "@easynet/agent-common";
|
|
6
|
+
import { createLangChainAgentTools } from "@easynet/agent-tool/api";
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
const APP_ROOT = resolve(__dirname, "..");
|
|
11
|
+
const CONFIG_DIR = resolve(APP_ROOT, "config");
|
|
12
|
+
|
|
13
|
+
function fail(message) {
|
|
14
|
+
console.error(`[validate-tools-config] ${message}`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function assert(condition, message) {
|
|
19
|
+
if (!condition) fail(message);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function asArray(value) {
|
|
23
|
+
return Array.isArray(value) ? value : [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizePath(p, baseDir = APP_ROOT) {
|
|
27
|
+
return p.startsWith("/") ? p : resolve(baseDir, p);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function loadYaml(path) {
|
|
31
|
+
const v = await loadYamlFile(path);
|
|
32
|
+
return v ?? {};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getCoreToolsOptions() {
|
|
36
|
+
return {
|
|
37
|
+
sandboxRoot: APP_ROOT,
|
|
38
|
+
allowedHosts: ["api.github.com", "duckduckgo.com", "www.duckduckgo.com"],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function resolveToolConfigPaths(reactAgentConfig, reactAgentDir) {
|
|
43
|
+
return {
|
|
44
|
+
toolsDefaultPath: normalizePath(reactAgentConfig?.spec?.tools?.ref ?? "../shared/tool.yaml", reactAgentDir),
|
|
45
|
+
toolsDevPath: normalizePath(reactAgentConfig?.spec?.tools?.development ?? "../shared/tool.development.yaml", reactAgentDir),
|
|
46
|
+
toolsProdPath: normalizePath(reactAgentConfig?.spec?.tools?.production ?? "../shared/tool.production.yaml", reactAgentDir),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function extractToolsConfigSummary(config) {
|
|
51
|
+
const spec = config?.spec ?? {};
|
|
52
|
+
const toolsNode = spec?.tools ?? {};
|
|
53
|
+
return {
|
|
54
|
+
tools: asArray(toolsNode?.list ?? toolsNode),
|
|
55
|
+
sandboxedPath: toolsNode?.sandboxedPath ?? spec?.sandboxedPath,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function validateDefaultConfig(defaultConfig) {
|
|
60
|
+
const summary = extractToolsConfigSummary(defaultConfig);
|
|
61
|
+
assert(typeof summary.sandboxedPath === "string", "tool.yaml missing sandboxedPath");
|
|
62
|
+
assert(summary.tools.length > 0, "tool.yaml tools must not be empty");
|
|
63
|
+
assert(
|
|
64
|
+
summary.tools.some(
|
|
65
|
+
(t) =>
|
|
66
|
+
typeof t === "string" &&
|
|
67
|
+
(t.startsWith("file:") || t.startsWith("npm:@easynet/agent-tool-buildin")),
|
|
68
|
+
),
|
|
69
|
+
"tool.yaml should use file:... or npm:@easynet/agent-tool-buildin",
|
|
70
|
+
);
|
|
71
|
+
return summary;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function validateVariantConfig(args) {
|
|
75
|
+
const { config, label, expectedSandboxedPath, defaultLoadedToolsLength, configFilePath } = args;
|
|
76
|
+
const summary = extractToolsConfigSummary(config);
|
|
77
|
+
assert(typeof summary.sandboxedPath === "string", `${label} missing sandboxedPath`);
|
|
78
|
+
assert(summary.sandboxedPath === expectedSandboxedPath, `${label} sandboxedPath should match tool.yaml`);
|
|
79
|
+
assert(summary.tools.length > 0, `${label} tools must not be empty`);
|
|
80
|
+
const loadedTools = createLangChainAgentTools({ configFilePath, coreTools: getCoreToolsOptions() });
|
|
81
|
+
assert(
|
|
82
|
+
loadedTools.length === defaultLoadedToolsLength,
|
|
83
|
+
`${label} count mismatch: default=${defaultLoadedToolsLength}, current=${loadedTools.length}`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function assertRequiredToolsLoaded(defaultLoadedTools) {
|
|
88
|
+
const names = new Set(defaultLoadedTools.map((t) => t.name));
|
|
89
|
+
const hasTool = (shortName) =>
|
|
90
|
+
Array.from(names).some((fullName) => fullName === shortName || fullName.endsWith(`.${shortName}`));
|
|
91
|
+
const required = [
|
|
92
|
+
"platformGetCapabilities",
|
|
93
|
+
"messagesListChats",
|
|
94
|
+
"messagesReadChat",
|
|
95
|
+
"messagesSendByHandle",
|
|
96
|
+
"notesList",
|
|
97
|
+
"notesRead",
|
|
98
|
+
"notesCreate",
|
|
99
|
+
"remindersList",
|
|
100
|
+
"remindersCreate",
|
|
101
|
+
"calendarListEvents",
|
|
102
|
+
"calendarCreateEvent",
|
|
103
|
+
"safariGetActiveTab",
|
|
104
|
+
"safariReadPageContent",
|
|
105
|
+
"cronListEntries",
|
|
106
|
+
"cronSetTaggedEntry",
|
|
107
|
+
"gitStatus",
|
|
108
|
+
"ghRead",
|
|
109
|
+
];
|
|
110
|
+
for (const name of required) {
|
|
111
|
+
assert(hasTool(name), `required tool not loaded: ${name}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function main() {
|
|
116
|
+
const appYamlPath = resolve(CONFIG_DIR, "app.yaml");
|
|
117
|
+
assert(existsSync(appYamlPath), `missing config file: ${appYamlPath}`);
|
|
118
|
+
|
|
119
|
+
const appConfig = await loadYaml(appYamlPath);
|
|
120
|
+
const appConfigDir = dirname(appYamlPath);
|
|
121
|
+
const reactAgentRef = appConfig?.spec?.agents?.list?.react?.ref;
|
|
122
|
+
const reactAgentYamlPath = normalizePath(reactAgentRef ?? "./agents/react/agent.yaml", appConfigDir);
|
|
123
|
+
assert(existsSync(reactAgentYamlPath), `react agent config not found: ${reactAgentYamlPath}`);
|
|
124
|
+
const reactAgentConfig = await loadYaml(reactAgentYamlPath);
|
|
125
|
+
const reactAgentDir = dirname(reactAgentYamlPath);
|
|
126
|
+
|
|
127
|
+
const { toolsDefaultPath, toolsDevPath, toolsProdPath } = resolveToolConfigPaths(reactAgentConfig, reactAgentDir);
|
|
128
|
+
|
|
129
|
+
assert(existsSync(toolsDefaultPath), `tool config not found: ${toolsDefaultPath}`);
|
|
130
|
+
|
|
131
|
+
const defaultConfig = await loadYaml(toolsDefaultPath);
|
|
132
|
+
const hasDevFile = existsSync(toolsDevPath);
|
|
133
|
+
const hasProdFile = existsSync(toolsProdPath);
|
|
134
|
+
const devConfig = hasDevFile ? await loadYaml(toolsDevPath) : null;
|
|
135
|
+
const prodConfig = hasProdFile ? await loadYaml(toolsProdPath) : null;
|
|
136
|
+
|
|
137
|
+
const { sandboxedPath: defaultSandboxedPath } = validateDefaultConfig(defaultConfig);
|
|
138
|
+
const defaultLoadedTools = createLangChainAgentTools({
|
|
139
|
+
configFilePath: toolsDefaultPath,
|
|
140
|
+
coreTools: getCoreToolsOptions(),
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
assert(defaultLoadedTools.length > 0, "tool.yaml loads 0 tools");
|
|
144
|
+
|
|
145
|
+
if (devConfig) {
|
|
146
|
+
validateVariantConfig({
|
|
147
|
+
config: devConfig,
|
|
148
|
+
label: "tool.development.yaml",
|
|
149
|
+
expectedSandboxedPath: defaultSandboxedPath,
|
|
150
|
+
defaultLoadedToolsLength: defaultLoadedTools.length,
|
|
151
|
+
configFilePath: toolsDevPath,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (prodConfig) {
|
|
156
|
+
validateVariantConfig({
|
|
157
|
+
config: prodConfig,
|
|
158
|
+
label: "tool.production.yaml",
|
|
159
|
+
expectedSandboxedPath: defaultSandboxedPath,
|
|
160
|
+
defaultLoadedToolsLength: defaultLoadedTools.length,
|
|
161
|
+
configFilePath: toolsProdPath,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
assertRequiredToolsLoaded(defaultLoadedTools);
|
|
166
|
+
|
|
167
|
+
console.log(
|
|
168
|
+
`[validate-tools-config] OK: default=${defaultLoadedTools.length}, devFile=${hasDevFile}, prodFile=${hasProdFile}`,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
main().catch((error) => {
|
|
173
|
+
fail(error instanceof Error ? error.message : String(error));
|
|
174
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { asObject, resolveKindResourceFile } from "@easynet/agent-common";
|
|
2
|
+
import {
|
|
3
|
+
createRuntimeConfig,
|
|
4
|
+
getModelsConfigPath as getRuntimeModelsConfigPath,
|
|
5
|
+
getMemoryConfigPath as getRuntimeMemoryConfigPath,
|
|
6
|
+
getToolConfigPath as getRuntimeToolConfigPath,
|
|
7
|
+
resolveDefaultAgentName as resolveRuntimeDefaultAgentName,
|
|
8
|
+
type AgentProfileConfig,
|
|
9
|
+
} from "@easynet/agent-runtime";
|
|
10
|
+
|
|
11
|
+
type IMessageAppSpec = {
|
|
12
|
+
agent?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export interface AppConfig {
|
|
16
|
+
app?: {
|
|
17
|
+
agent?: Record<string, AgentProfileConfig>;
|
|
18
|
+
defaultAgent?: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface AppConfigDefaults {
|
|
23
|
+
modelsPath?: string;
|
|
24
|
+
memoryPath?: string;
|
|
25
|
+
toolPath?: string;
|
|
26
|
+
toolDevPath?: string;
|
|
27
|
+
toolProdPath?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function loadAppConfig(configPath?: string): Promise<AppConfig> {
|
|
31
|
+
const appResource = await resolveKindResourceFile<IMessageAppSpec>(configPath ?? "config/app.yaml", {
|
|
32
|
+
baseDir: process.cwd(),
|
|
33
|
+
expectedApiVersion: "easynet.world/v1",
|
|
34
|
+
expectedKind: "AppConfig",
|
|
35
|
+
});
|
|
36
|
+
const spec = asObject(appResource.spec) as IMessageAppSpec | undefined;
|
|
37
|
+
const runtimeConfig = await createRuntimeConfig({
|
|
38
|
+
configPath,
|
|
39
|
+
overrides: {
|
|
40
|
+
app: {
|
|
41
|
+
defaultAgent: spec?.agent,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
const defaultAgent = resolveRuntimeDefaultAgentName(runtimeConfig, spec?.agent);
|
|
46
|
+
return {
|
|
47
|
+
app: {
|
|
48
|
+
agent: runtimeConfig.app?.agent,
|
|
49
|
+
defaultAgent,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function getModelsConfigPath(
|
|
55
|
+
config: AppConfig,
|
|
56
|
+
agentName?: string,
|
|
57
|
+
defaults?: AppConfigDefaults,
|
|
58
|
+
): string {
|
|
59
|
+
return getRuntimeModelsConfigPath(config, agentName, defaults);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function getMemoryConfigPath(
|
|
63
|
+
config: AppConfig,
|
|
64
|
+
agentName?: string,
|
|
65
|
+
defaults?: AppConfigDefaults,
|
|
66
|
+
): string {
|
|
67
|
+
return getRuntimeMemoryConfigPath(config, agentName, defaults);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function getToolConfigPath(
|
|
71
|
+
config: AppConfig,
|
|
72
|
+
agentName?: string,
|
|
73
|
+
defaults?: AppConfigDefaults,
|
|
74
|
+
): string {
|
|
75
|
+
return getRuntimeToolConfigPath(config, agentName, defaults);
|
|
76
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared runtime context: LLM, memory, tools.
|
|
3
|
+
* Built once and passed to both ReAct and Deep agents.
|
|
4
|
+
*/
|
|
5
|
+
import {
|
|
6
|
+
createContextBuilders,
|
|
7
|
+
type AppContextBuilders,
|
|
8
|
+
type BotContext,
|
|
9
|
+
type BotTool,
|
|
10
|
+
type CreateContextOptions,
|
|
11
|
+
} from "@easynet/agent-runtime";
|
|
12
|
+
import {
|
|
13
|
+
loadAppConfig,
|
|
14
|
+
getModelsConfigPath,
|
|
15
|
+
getMemoryConfigPath,
|
|
16
|
+
getToolConfigPath,
|
|
17
|
+
type AppConfig,
|
|
18
|
+
} from "./config.js";
|
|
19
|
+
|
|
20
|
+
export type { BotContext, BotTool, CreateContextOptions };
|
|
21
|
+
|
|
22
|
+
const builders: AppContextBuilders = createContextBuilders<AppConfig>({
|
|
23
|
+
configApi: {
|
|
24
|
+
loadAgentConfig: loadAppConfig,
|
|
25
|
+
getModelsConfigPath: (config: AppConfig, agentName?: string) => getModelsConfigPath(config, agentName),
|
|
26
|
+
getMemoryConfigPath: (config: AppConfig, agentName?: string) => getMemoryConfigPath(config, agentName),
|
|
27
|
+
getToolConfigPath: (config: AppConfig, agentName?: string) => getToolConfigPath(config, agentName),
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const createAgentLlm: AppContextBuilders["createAgentLlm"] = builders.createAgentLlm;
|
|
32
|
+
export const createAgentMemory: AppContextBuilders["createAgentMemory"] = builders.createAgentMemory;
|
|
33
|
+
export const createAgentTools: AppContextBuilders["createAgentTools"] = builders.createAgentTools;
|
|
34
|
+
export const createAgent: AppContextBuilders["createAgent"] = builders.createAgent;
|
|
35
|
+
export const createBotContext: AppContextBuilders["createBotContext"] = builders.createBotContext;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* iMessageBot: ReAct agent (LangChain) + Deep agent (DeepAgents).
|
|
4
|
+
* Usage:
|
|
5
|
+
* npm start # interactive: choose agent then chat
|
|
6
|
+
* npm run react # use ReAct agent
|
|
7
|
+
* npm run deep # use Deep agent
|
|
8
|
+
* node dist/index.js react "Your question"
|
|
9
|
+
* node dist/index.js deep "Your question"
|
|
10
|
+
*/
|
|
11
|
+
import { runAppCli } from "@easynet/agent-runtime";
|
|
12
|
+
import { createBotContext } from "./context.js";
|
|
13
|
+
|
|
14
|
+
runAppCli({
|
|
15
|
+
appName: "iMessageBot",
|
|
16
|
+
createBotContext,
|
|
17
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"rootDir": "src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"declarationMap": true,
|
|
13
|
+
"sourceMap": true,
|
|
14
|
+
"resolveJsonModule": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*"],
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ['**']
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: ['**']
|
|
8
|
+
repository_dispatch:
|
|
9
|
+
types:
|
|
10
|
+
- easynet-package-updated
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
test:
|
|
18
|
+
name: Test & Build
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
timeout-minutes: 25
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- name: Setup Node.js
|
|
26
|
+
uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: '20'
|
|
29
|
+
cache: 'npm'
|
|
30
|
+
registry-url: 'https://registry.npmjs.org'
|
|
31
|
+
|
|
32
|
+
- name: Force npm registry to npmjs.org
|
|
33
|
+
run: |
|
|
34
|
+
touch .npmrc
|
|
35
|
+
grep -q '^registry=https://registry.npmjs.org' .npmrc || echo "registry=https://registry.npmjs.org/" >> .npmrc
|
|
36
|
+
grep -q '@easynet:registry=' .npmrc || echo "@easynet:registry=https://registry.npmjs.org/" >> .npmrc
|
|
37
|
+
grep -q '@wallee:registry=' .npmrc || echo "@wallee:registry=https://registry.npmjs.org/" >> .npmrc
|
|
38
|
+
|
|
39
|
+
- name: Install dependencies
|
|
40
|
+
env:
|
|
41
|
+
NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/"
|
|
42
|
+
run: npm install --legacy-peer-deps
|
|
43
|
+
|
|
44
|
+
- name: Build
|
|
45
|
+
run: npm run build --if-present
|
|
46
|
+
|
|
47
|
+
- name: Typecheck
|
|
48
|
+
run: npm run typecheck --if-present
|
|
49
|
+
|
|
50
|
+
- name: Test
|
|
51
|
+
run: npm test --if-present
|
|
52
|
+
|
|
53
|
+
- name: Diagnostics (on failure)
|
|
54
|
+
if: failure()
|
|
55
|
+
run: |
|
|
56
|
+
echo "Node: $(node -v) | npm: $(npm -v)"
|
|
57
|
+
echo "--- .npmrc ---"
|
|
58
|
+
cat .npmrc 2>&1 || true
|
|
59
|
+
echo "--- npm config ---"
|
|
60
|
+
npm config list 2>&1 || true
|
|
61
|
+
npm ls --depth=0 2>&1 | head -50
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- master
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
repository_dispatch:
|
|
9
|
+
types:
|
|
10
|
+
- easynet-package-updated
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: write
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
release:
|
|
21
|
+
name: Release
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
timeout-minutes: 30
|
|
24
|
+
steps:
|
|
25
|
+
- name: Checkout
|
|
26
|
+
uses: actions/checkout@v4
|
|
27
|
+
with:
|
|
28
|
+
fetch-depth: 0
|
|
29
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
30
|
+
|
|
31
|
+
- name: Setup Node.js
|
|
32
|
+
uses: actions/setup-node@v4
|
|
33
|
+
with:
|
|
34
|
+
node-version: '20'
|
|
35
|
+
cache: 'npm'
|
|
36
|
+
registry-url: 'https://registry.npmjs.org'
|
|
37
|
+
|
|
38
|
+
- name: Force npm registry to npmjs.org
|
|
39
|
+
run: |
|
|
40
|
+
touch .npmrc
|
|
41
|
+
grep -q '^registry=https://registry.npmjs.org' .npmrc || echo "registry=https://registry.npmjs.org/" >> .npmrc
|
|
42
|
+
grep -q '@easynet:registry=' .npmrc || echo "@easynet:registry=https://registry.npmjs.org/" >> .npmrc
|
|
43
|
+
grep -q '@wallee:registry=' .npmrc || echo "@wallee:registry=https://registry.npmjs.org/" >> .npmrc
|
|
44
|
+
|
|
45
|
+
- name: Use @easynet deps from npm (CI has no file:../../)
|
|
46
|
+
run: |
|
|
47
|
+
node -e "
|
|
48
|
+
const fs = require('fs');
|
|
49
|
+
const pkgPath = 'package.json';
|
|
50
|
+
const p = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
51
|
+
const deps = { ...p.dependencies, ...p.devDependencies };
|
|
52
|
+
let changed = false;
|
|
53
|
+
for (const [name, v] of Object.entries(deps)) {
|
|
54
|
+
if (name.startsWith('@easynet/') && typeof v === 'string' && v.startsWith('file:')) {
|
|
55
|
+
if (p.dependencies[name]) { p.dependencies[name] = 'latest'; changed = true; }
|
|
56
|
+
if (p.devDependencies[name]) { p.devDependencies[name] = 'latest'; changed = true; }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (changed) fs.writeFileSync(pkgPath, JSON.stringify(p, null, 2) + '\n');
|
|
60
|
+
"
|
|
61
|
+
|
|
62
|
+
- name: Install dependencies
|
|
63
|
+
env:
|
|
64
|
+
NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/"
|
|
65
|
+
run: npm install --legacy-peer-deps
|
|
66
|
+
|
|
67
|
+
- name: Build
|
|
68
|
+
run: npm run build --if-present
|
|
69
|
+
|
|
70
|
+
- name: Typecheck
|
|
71
|
+
run: npm run typecheck --if-present
|
|
72
|
+
|
|
73
|
+
- name: Test
|
|
74
|
+
run: npm test --if-present
|
|
75
|
+
|
|
76
|
+
- name: Release
|
|
77
|
+
env:
|
|
78
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
79
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
80
|
+
run: npx semantic-release
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** @type {import('semantic-release').GlobalConfig} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
branches: ['master'],
|
|
4
|
+
plugins: [
|
|
5
|
+
[
|
|
6
|
+
'@semantic-release/commit-analyzer',
|
|
7
|
+
{
|
|
8
|
+
releaseRules: [
|
|
9
|
+
{ type: 'feat', release: 'patch' },
|
|
10
|
+
{ type: 'fix', release: 'patch' },
|
|
11
|
+
{ type: 'docs', release: 'patch' },
|
|
12
|
+
{ type: 'chore', release: 'patch' },
|
|
13
|
+
{ type: 'refactor', release: 'patch' },
|
|
14
|
+
{ type: 'perf', release: 'patch' },
|
|
15
|
+
{ type: 'test', release: 'patch' },
|
|
16
|
+
{ type: 'ci', release: 'patch' },
|
|
17
|
+
{ type: 'build', release: 'patch' },
|
|
18
|
+
{ message: '*', release: 'patch' },
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
'@semantic-release/release-notes-generator',
|
|
23
|
+
'@semantic-release/npm',
|
|
24
|
+
'@semantic-release/git',
|
|
25
|
+
],
|
|
26
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# iTermBot
|
|
2
|
+
|
|
3
|
+
iTermBot is an application built on the **@easynet** agent framework. It runs two agents:
|
|
4
|
+
|
|
5
|
+
1. **ReAct agent** — LangChain `createAgent` (ReAct pattern) with tools and memory.
|
|
6
|
+
2. **Deep agent** — DeepAgents `createDeepAgent` with a persistent store backed by agent-memory.
|
|
7
|
+
|
|
8
|
+
Both agents share:
|
|
9
|
+
|
|
10
|
+
- **@easynet/agent-common** — YAML config (app, paths).
|
|
11
|
+
- **@easynet/agent-model** — LLM and embedding models (falls back to module default config).
|
|
12
|
+
- **@easynet/agent-memory** — Agent memory (recall/inject for ReAct; store adapter for Deep).
|
|
13
|
+
- **@easynet/agent-tool** + **@easynet/agent-tool-buildin** — Tools (FS, HTTP, util, exec, etc.).
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- Node.js >= 18
|
|
18
|
+
- Ollama (or another OpenAI-compatible endpoint) for the LLM. Default config uses `http://localhost:11434/v1` and `qwen3:0.6b`.
|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
Build from source workspace:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
cd apps/itermbot
|
|
26
|
+
npm install
|
|
27
|
+
npm run build
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Tool support uses agent-tool’s `@easynet/agent-tool` and `@easynet/agent-tool-buildin` from the npm registry.
|
|
31
|
+
|
|
32
|
+
## Config
|
|
33
|
+
|
|
34
|
+
| File | Purpose |
|
|
35
|
+
|------|--------|
|
|
36
|
+
| `config/app.yaml` | App-level settings (`agent`, `printSteps`, prompt templates). |
|
|
37
|
+
|
|
38
|
+
Agent profile defaults (model/memory/tool/skills) are resolved by `@easynet/agent-runtime`.
|
|
39
|
+
Top-level app config only overrides runtime defaults.
|
|
40
|
+
|
|
41
|
+
Tool config now falls back to `@easynet/agent-tool` module defaults when app-level tool config is not provided.
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
- **Interactive (ReAct agent):**
|
|
46
|
+
```bash
|
|
47
|
+
npm start
|
|
48
|
+
# or
|
|
49
|
+
npm run react
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- **Interactive (Deep agent):**
|
|
53
|
+
```bash
|
|
54
|
+
npm run deep
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- **One-shot query:**
|
|
58
|
+
```bash
|
|
59
|
+
node dist/index.js react "What time is it?"
|
|
60
|
+
node dist/index.js deep "Remember I prefer short answers."
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Scripts
|
|
64
|
+
|
|
65
|
+
| Script | Description |
|
|
66
|
+
|--------|-------------|
|
|
67
|
+
| `npm run build` | Compile TypeScript to `dist/`. |
|
|
68
|
+
| `npm start` | Run interactive with ReAct agent. |
|
|
69
|
+
| `npm run react` | Same as start (ReAct). |
|
|
70
|
+
| `npm run deep` | Interactive with Deep agent. |
|
|
71
|
+
| `npm run typecheck` | Type-check only. |
|
|
72
|
+
| `npm run test:llm` | Test LLM config (scripts/test-llm.mjs). |
|
|
73
|
+
|
|
74
|
+
## Architecture
|
|
75
|
+
|
|
76
|
+
- **src/index.ts** — CLI startup and orchestration.
|
|
77
|
+
- **src/context.ts** — Shared `BotContext` builders (LLM/memory/tools/skills).
|
|
78
|
+
- **src/config.ts** — App-level override adapter on top of runtime config.
|
|
79
|
+
- **src/startup/** — startup UI, diagnostics, and panel color bootstrapping.
|
|
80
|
+
- **src/iterm/** — iTerm session routing and target session prompt injection.
|
|
81
|
+
|
|
82
|
+
Both agents use the same LLM, memory backend, and tool set; only the orchestration (ReAct vs Deep) differs.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
apiVersion: easynet.world/v1
|
|
2
|
+
kind: AppConfig
|
|
3
|
+
metadata:
|
|
4
|
+
name: itermbot
|
|
5
|
+
spec:
|
|
6
|
+
agent: react
|
|
7
|
+
|
|
8
|
+
printSteps: false
|
|
9
|
+
|
|
10
|
+
promptTemplates:
|
|
11
|
+
itermPolicy: |
|
|
12
|
+
## iTerm Operating Policy
|
|
13
|
+
- Target panel output is the remote source of truth.
|
|
14
|
+
- Never use local machine commands for system/project data collection.
|
|
15
|
+
- For remote operations/investigation, use `itermRunCommandInSession` in target panel.
|
|
16
|
+
- For current screen/panel analysis, never ask user to paste text; capture via no-op `:`.
|
|
17
|
+
- For full coverage, paginate with `outputOffsetLines + maxOutputLines`, summarize by chunk, then merge.
|
|
18
|
+
- If output is long, use bounded chunk analysis with interim summaries and one final conclusion.
|
|
19
|
+
- Prefer fast/low-cost commands; avoid heavy full scans/builds/tests unless required.
|
|
20
|
+
- Host may auto-update target panel when focus moves to a non-chat panel.
|
|
21
|
+
- Final response must be valid Markdown with stable formatting.
|
|
22
|
+
- Host may auto-recover target routing (reuse non-chat pane or auto-split); if still failing, ask user.
|
|
23
|
+
targetSession: |
|
|
24
|
+
## Target Panel Session
|
|
25
|
+
Routed target panel (may change at runtime):
|
|
26
|
+
- sessionId: "{{sessionId}}"
|
|
27
|
+
- windowId: {{windowId}}
|
|
28
|
+
- tabIndex: {{tabIndex}}
|
|
29
|
+
Never use `windowId: 0` and never guess IDs.
|