palmier 0.5.0 → 0.5.2
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/dist/agents/agent-instructions.md +7 -11
- package/dist/agents/agent.d.ts +8 -3
- package/dist/agents/agent.js +7 -1
- package/dist/agents/claude.d.ts +2 -1
- package/dist/agents/claude.js +10 -5
- package/dist/agents/codex.d.ts +2 -1
- package/dist/agents/codex.js +10 -6
- package/dist/agents/copilot.d.ts +2 -1
- package/dist/agents/copilot.js +10 -3
- package/dist/agents/gemini.d.ts +2 -1
- package/dist/agents/gemini.js +11 -7
- package/dist/agents/kimi.d.ts +9 -0
- package/dist/agents/kimi.js +35 -0
- package/dist/agents/openclaw.d.ts +2 -1
- package/dist/agents/openclaw.js +3 -1
- package/dist/agents/qwen.d.ts +9 -0
- package/dist/agents/qwen.js +32 -0
- package/dist/agents/shared-prompt.d.ts +1 -1
- package/dist/agents/shared-prompt.js +6 -2
- package/dist/commands/run.js +22 -5
- package/dist/platform/windows.js +17 -1
- package/dist/rpc-handler.js +15 -4
- package/dist/task.d.ts +13 -3
- package/dist/task.js +39 -7
- package/dist/transports/http-transport.js +29 -9
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/agents/agent-instructions.md +7 -11
- package/src/agents/agent.ts +16 -4
- package/src/agents/claude.ts +11 -6
- package/src/agents/codex.ts +11 -7
- package/src/agents/copilot.ts +10 -4
- package/src/agents/gemini.ts +12 -8
- package/src/agents/kimi.ts +37 -0
- package/src/agents/openclaw.ts +4 -2
- package/src/agents/qwen.ts +34 -0
- package/src/agents/shared-prompt.ts +6 -2
- package/src/commands/run.ts +24 -5
- package/src/platform/windows.ts +14 -1
- package/src/rpc-handler.ts +17 -4
- package/src/task.ts +43 -8
- package/src/transports/http-transport.ts +34 -9
- package/src/types.ts +1 -0
- package/test/agent-instructions.test.ts +31 -0
|
@@ -2,23 +2,19 @@ You are an AI agent executing a task on behalf of the user via the Palmier platf
|
|
|
2
2
|
|
|
3
3
|
## Reporting Output
|
|
4
4
|
|
|
5
|
-
If you generate report or output files, print each file path on its own line
|
|
6
|
-
[PALMIER_REPORT]
|
|
7
|
-
[PALMIER_REPORT] summary.md
|
|
5
|
+
If you generate report or output files, print each file path on its own line using this exact format (no code block):
|
|
6
|
+
`[PALMIER_REPORT] <filename>`
|
|
8
7
|
|
|
9
8
|
## Completion
|
|
10
9
|
|
|
11
|
-
When you are done, output exactly one of these markers as the very last line:
|
|
12
|
-
- Success: [PALMIER_TASK_SUCCESS]
|
|
13
|
-
- Failure: [PALMIER_TASK_FAILURE]
|
|
14
|
-
Do not wrap them in code blocks or add text on the same line.
|
|
10
|
+
When you are done, output exactly one of these markers as the very last line (no code block, no other text on the same line):
|
|
11
|
+
- Success: `[PALMIER_TASK_SUCCESS]`
|
|
12
|
+
- Failure: `[PALMIER_TASK_FAILURE]`
|
|
15
13
|
|
|
16
14
|
## Permissions
|
|
17
15
|
|
|
18
|
-
If the task fails because a tool was denied or you lack the required permissions, print each required permission on its own line
|
|
19
|
-
[PALMIER_PERMISSION]
|
|
20
|
-
[PALMIER_PERMISSION] Bash(npm test) | Run the test suite via npm
|
|
21
|
-
[PALMIER_PERMISSION] Write | Write generated output files
|
|
16
|
+
If the task fails because a tool was denied or you lack the required permissions, print each required permission on its own line using this exact format (no code block):
|
|
17
|
+
`[PALMIER_PERMISSION] <tool_name> | <description>`
|
|
22
18
|
|
|
23
19
|
## HTTP Endpoints
|
|
24
20
|
|
package/dist/agents/agent.d.ts
CHANGED
|
@@ -13,9 +13,13 @@ export interface AgentTool {
|
|
|
13
13
|
/** Return the command and args used to generate a plan from a prompt. */
|
|
14
14
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
15
15
|
/** Return the command and args used to run a task. If followupPrompt is provided, use it instead of the task's prompt,
|
|
16
|
-
* and treat it as a continuation of the original run (reuse the same session, etc).
|
|
17
|
-
* permissions granted for this run only
|
|
18
|
-
|
|
16
|
+
* and treat it as a continuation of the original run (reuse the same session, etc).
|
|
17
|
+
* extraPermissions: pass an array of RequiredPermission for transient permissions granted for this run only,
|
|
18
|
+
* or pass `"yolo"` to enable yolo mode (auto-approve all tools, skip permission instructions). */
|
|
19
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
20
|
+
/** Whether this agent supports permission overrides (e.g. --allowedTools).
|
|
21
|
+
* If false, the permissions section is omitted from agent instructions. */
|
|
22
|
+
supportsPermissions: boolean;
|
|
19
23
|
/** Detect whether the agent CLI is available and perform any agent-specific
|
|
20
24
|
* initialization. Returns true if the agent was detected and initialized successfully. */
|
|
21
25
|
init(): Promise<boolean>;
|
|
@@ -23,6 +27,7 @@ export interface AgentTool {
|
|
|
23
27
|
export interface DetectedAgent {
|
|
24
28
|
key: string;
|
|
25
29
|
label: string;
|
|
30
|
+
supportsPermissions: boolean;
|
|
26
31
|
}
|
|
27
32
|
export declare function detectAgents(): Promise<DetectedAgent[]>;
|
|
28
33
|
export declare function getAgent(name: string): AgentTool;
|
package/dist/agents/agent.js
CHANGED
|
@@ -3,12 +3,16 @@ import { GeminiAgent } from "./gemini.js";
|
|
|
3
3
|
import { CodexAgent } from "./codex.js";
|
|
4
4
|
import { OpenClawAgent } from "./openclaw.js";
|
|
5
5
|
import { CopilotAgent } from "./copilot.js";
|
|
6
|
+
import { QwenAgent } from "./qwen.js";
|
|
7
|
+
import { KimiAgent } from "./kimi.js";
|
|
6
8
|
const agentRegistry = {
|
|
7
9
|
claude: new ClaudeAgent(),
|
|
8
10
|
gemini: new GeminiAgent(),
|
|
9
11
|
codex: new CodexAgent(),
|
|
10
12
|
openclaw: new OpenClawAgent(),
|
|
11
13
|
copilot: new CopilotAgent(),
|
|
14
|
+
qwen: new QwenAgent(),
|
|
15
|
+
kimi: new KimiAgent(),
|
|
12
16
|
};
|
|
13
17
|
const agentLabels = {
|
|
14
18
|
claude: "Claude Code",
|
|
@@ -16,6 +20,8 @@ const agentLabels = {
|
|
|
16
20
|
codex: "Codex CLI",
|
|
17
21
|
openclaw: "OpenClaw",
|
|
18
22
|
copilot: "Copilot CLI",
|
|
23
|
+
qwen: "Qwen Code",
|
|
24
|
+
kimi: "Kimi Code",
|
|
19
25
|
};
|
|
20
26
|
export async function detectAgents() {
|
|
21
27
|
const detected = [];
|
|
@@ -23,7 +29,7 @@ export async function detectAgents() {
|
|
|
23
29
|
const label = agentLabels[key] ?? key;
|
|
24
30
|
const ok = await agent.init();
|
|
25
31
|
if (ok)
|
|
26
|
-
detected.push({ key, label });
|
|
32
|
+
detected.push({ key, label, supportsPermissions: agent.supportsPermissions });
|
|
27
33
|
}
|
|
28
34
|
return detected;
|
|
29
35
|
}
|
package/dist/agents/claude.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
2
|
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
3
|
export declare class ClaudeAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
4
5
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
5
|
-
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[]): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
6
7
|
init(): Promise<boolean>;
|
|
7
8
|
}
|
|
8
9
|
//# sourceMappingURL=claude.d.ts.map
|
package/dist/agents/claude.js
CHANGED
|
@@ -2,6 +2,7 @@ import { execSync } from "child_process";
|
|
|
2
2
|
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
3
|
import { SHELL } from "../platform/index.js";
|
|
4
4
|
export class ClaudeAgent {
|
|
5
|
+
supportsPermissions = true;
|
|
5
6
|
getPlanGenerationCommandLine(prompt) {
|
|
6
7
|
return {
|
|
7
8
|
command: "claude",
|
|
@@ -9,11 +10,15 @@ export class ClaudeAgent {
|
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
args.push("--allowedTools",
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
15
|
+
const args = ["--permission-mode", yolo ? "bypassPermissions" : "acceptEdits", "-p"];
|
|
16
|
+
if (!yolo) {
|
|
17
|
+
args.push("--allowedTools", "WebFetch");
|
|
18
|
+
const allPerms = [...(task.frontmatter.permissions ?? []), ...(extraPermissions ?? [])];
|
|
19
|
+
for (const p of allPerms) {
|
|
20
|
+
args.push("--allowedTools", p.name);
|
|
21
|
+
}
|
|
17
22
|
}
|
|
18
23
|
if (followupPrompt) {
|
|
19
24
|
args.push("-c");
|
package/dist/agents/codex.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
2
|
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
3
|
export declare class CodexAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
4
5
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
5
|
-
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[]): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
6
7
|
init(): Promise<boolean>;
|
|
7
8
|
}
|
|
8
9
|
//# sourceMappingURL=codex.d.ts.map
|
package/dist/agents/codex.js
CHANGED
|
@@ -2,6 +2,7 @@ import { execSync } from "child_process";
|
|
|
2
2
|
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
3
|
import { SHELL } from "../platform/index.js";
|
|
4
4
|
export class CodexAgent {
|
|
5
|
+
supportsPermissions = true;
|
|
5
6
|
getPlanGenerationCommandLine(prompt) {
|
|
6
7
|
return {
|
|
7
8
|
command: "codex",
|
|
@@ -9,13 +10,16 @@ export class CodexAgent {
|
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
12
|
-
const
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
13
15
|
// Using danger-full-access until workspace-write is fixed: https://github.com/openai/codex/issues/12572
|
|
14
|
-
const args = ["exec", "--
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const args = ["exec", "--skip-git-repo-check", "--sandbox", "danger-full-access"];
|
|
17
|
+
if (!yolo) {
|
|
18
|
+
const allPerms = [...(task.frontmatter.permissions ?? []), ...(extraPermissions ?? [])];
|
|
19
|
+
for (const p of allPerms) {
|
|
20
|
+
args.push("--config");
|
|
21
|
+
args.push(`apps.${p.name}.default_tools_approval_mode="approve"`);
|
|
22
|
+
}
|
|
19
23
|
}
|
|
20
24
|
if (followupPrompt) {
|
|
21
25
|
args.push("resume", "--last");
|
package/dist/agents/copilot.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
2
|
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
3
|
export declare class CopilotAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
4
5
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
5
|
-
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[]): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
6
7
|
init(): Promise<boolean>;
|
|
7
8
|
}
|
|
8
9
|
//# sourceMappingURL=copilot.d.ts.map
|
package/dist/agents/copilot.js
CHANGED
|
@@ -2,6 +2,7 @@ import { execSync } from "child_process";
|
|
|
2
2
|
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
3
|
import { SHELL } from "../platform/index.js";
|
|
4
4
|
export class CopilotAgent {
|
|
5
|
+
supportsPermissions = false;
|
|
5
6
|
getPlanGenerationCommandLine(prompt) {
|
|
6
7
|
return {
|
|
7
8
|
command: "copilot",
|
|
@@ -9,10 +10,16 @@ export class CopilotAgent {
|
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
12
|
-
const
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
13
15
|
const args = ["-p", prompt];
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
if (yolo) {
|
|
17
|
+
args.push("--yolo");
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const allPerms = [...(task.frontmatter.permissions ?? []), ...(extraPermissions ?? [])];
|
|
21
|
+
args.push(`--allow-tool=${["web_fetch", ...allPerms.map((p) => p.name)].join(",")}`);
|
|
22
|
+
}
|
|
16
23
|
if (followupPrompt) {
|
|
17
24
|
args.push("--continue");
|
|
18
25
|
}
|
package/dist/agents/gemini.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
2
|
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
3
|
export declare class GeminiAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
4
5
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
5
|
-
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[]): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
6
7
|
init(): Promise<boolean>;
|
|
7
8
|
}
|
|
8
9
|
//# sourceMappingURL=gemini.d.ts.map
|
package/dist/agents/gemini.js
CHANGED
|
@@ -2,6 +2,7 @@ import { execSync } from "child_process";
|
|
|
2
2
|
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
3
|
import { SHELL } from "../platform/index.js";
|
|
4
4
|
export class GeminiAgent {
|
|
5
|
+
supportsPermissions = true;
|
|
5
6
|
getPlanGenerationCommandLine(prompt) {
|
|
6
7
|
return {
|
|
7
8
|
command: "gemini",
|
|
@@ -9,19 +10,22 @@ export class GeminiAgent {
|
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
15
|
+
const args = ["--approval-mode", yolo ? "yolo" : "auto_edit"];
|
|
16
|
+
if (!yolo) {
|
|
17
|
+
const tools = ["run_shell_command", "web_fetch"];
|
|
18
|
+
const allPerms = [...(task.frontmatter.permissions ?? []), ...(extraPermissions ?? [])];
|
|
16
19
|
for (const p of allPerms) {
|
|
17
|
-
|
|
20
|
+
tools.push(p.name);
|
|
18
21
|
}
|
|
22
|
+
args.push("--allowed-tools", tools.join(","));
|
|
19
23
|
}
|
|
20
24
|
if (followupPrompt) {
|
|
21
25
|
args.push("--resume");
|
|
22
26
|
} // continue mode for followups
|
|
23
|
-
args.push("--prompt",
|
|
24
|
-
return { command: "gemini", args };
|
|
27
|
+
args.push("--prompt", "-"); // read prompt from stdin to avoid command line length limits
|
|
28
|
+
return { command: "gemini", args, stdin: prompt };
|
|
25
29
|
}
|
|
26
30
|
async init() {
|
|
27
31
|
try {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
|
+
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
|
+
export declare class KimiAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
5
|
+
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
7
|
+
init(): Promise<boolean>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=kimi.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
|
+
import { SHELL } from "../platform/index.js";
|
|
4
|
+
export class KimiAgent {
|
|
5
|
+
supportsPermissions = false;
|
|
6
|
+
getPlanGenerationCommandLine(prompt) {
|
|
7
|
+
return {
|
|
8
|
+
command: "kimi",
|
|
9
|
+
args: ["-p", prompt],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
15
|
+
const args = [];
|
|
16
|
+
if (yolo) {
|
|
17
|
+
args.push("--yolo");
|
|
18
|
+
}
|
|
19
|
+
if (followupPrompt) {
|
|
20
|
+
args.push("--continue");
|
|
21
|
+
}
|
|
22
|
+
args.push("-p", prompt);
|
|
23
|
+
return { command: "kimi", args };
|
|
24
|
+
}
|
|
25
|
+
async init() {
|
|
26
|
+
try {
|
|
27
|
+
execSync("kimi --version", { stdio: "ignore", shell: SHELL });
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=kimi.js.map
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
2
|
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
3
|
export declare class OpenClawAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
4
5
|
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
5
|
-
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[]): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
6
7
|
init(): Promise<boolean>;
|
|
7
8
|
}
|
|
8
9
|
//# sourceMappingURL=openclaw.d.ts.map
|
package/dist/agents/openclaw.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { execSync } from "child_process";
|
|
2
2
|
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
3
|
export class OpenClawAgent {
|
|
4
|
+
supportsPermissions = false;
|
|
4
5
|
getPlanGenerationCommandLine(prompt) {
|
|
5
6
|
return {
|
|
6
7
|
command: "openclaw",
|
|
@@ -8,7 +9,8 @@ export class OpenClawAgent {
|
|
|
8
9
|
};
|
|
9
10
|
}
|
|
10
11
|
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
11
|
-
const
|
|
12
|
+
const yolo = extraPermissions === "yolo";
|
|
13
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
12
14
|
// OpenClaw does not support stdin as prompt.
|
|
13
15
|
const args = ["agent", "--local", "--session-id", task.frontmatter.id, "--message", prompt];
|
|
14
16
|
return { command: "openclaw", args };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedTask, RequiredPermission } from "../types.js";
|
|
2
|
+
import type { AgentTool, CommandLine } from "./agent.js";
|
|
3
|
+
export declare class QwenAgent implements AgentTool {
|
|
4
|
+
supportsPermissions: boolean;
|
|
5
|
+
getPlanGenerationCommandLine(prompt: string): CommandLine;
|
|
6
|
+
getTaskRunCommandLine(task: ParsedTask, followupPrompt?: string, extraPermissions?: RequiredPermission[] | "yolo"): CommandLine;
|
|
7
|
+
init(): Promise<boolean>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=qwen.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { getAgentInstructions } from "./shared-prompt.js";
|
|
3
|
+
import { SHELL } from "../platform/index.js";
|
|
4
|
+
export class QwenAgent {
|
|
5
|
+
supportsPermissions = false;
|
|
6
|
+
getPlanGenerationCommandLine(prompt) {
|
|
7
|
+
return {
|
|
8
|
+
command: "qwen",
|
|
9
|
+
args: ["-p", prompt],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
getTaskRunCommandLine(task, followupPrompt, extraPermissions) {
|
|
13
|
+
const yolo = extraPermissions === "yolo";
|
|
14
|
+
const prompt = followupPrompt ?? (getAgentInstructions(task.frontmatter.id, yolo || !this.supportsPermissions) + "\n\n" + (task.body || task.frontmatter.user_prompt));
|
|
15
|
+
const args = ["--approval-mode", yolo ? "yolo" : "auto-edit"];
|
|
16
|
+
if (followupPrompt) {
|
|
17
|
+
args.push("-c");
|
|
18
|
+
}
|
|
19
|
+
args.push("-p", prompt);
|
|
20
|
+
return { command: "qwen", args };
|
|
21
|
+
}
|
|
22
|
+
async init() {
|
|
23
|
+
try {
|
|
24
|
+
execSync("qwen --version", { stdio: "ignore", shell: SHELL });
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=qwen.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent instructions with the serve daemon's HTTP port and task ID baked in.
|
|
3
3
|
*/
|
|
4
|
-
export declare function getAgentInstructions(taskId: string): string;
|
|
4
|
+
export declare function getAgentInstructions(taskId: string, skipPermissions?: boolean): string;
|
|
5
5
|
export declare const TASK_SUCCESS_MARKER = "[PALMIER_TASK_SUCCESS]";
|
|
6
6
|
export declare const TASK_FAILURE_MARKER = "[PALMIER_TASK_FAILURE]";
|
|
7
7
|
export declare const TASK_REPORT_PREFIX = "[PALMIER_REPORT]";
|
|
@@ -7,11 +7,15 @@ const AGENT_INSTRUCTIONS_TEMPLATE = fs.readFileSync(path.join(__dirname, "agent-
|
|
|
7
7
|
/**
|
|
8
8
|
* Agent instructions with the serve daemon's HTTP port and task ID baked in.
|
|
9
9
|
*/
|
|
10
|
-
export function getAgentInstructions(taskId) {
|
|
10
|
+
export function getAgentInstructions(taskId, skipPermissions) {
|
|
11
11
|
const port = loadConfig().httpPort ?? 7400;
|
|
12
|
-
|
|
12
|
+
let instructions = AGENT_INSTRUCTIONS_TEMPLATE
|
|
13
13
|
.replace(/\{\{PORT\}\}/g, String(port))
|
|
14
14
|
.replace(/\{\{TASK_ID\}\}/g, taskId);
|
|
15
|
+
if (skipPermissions) {
|
|
16
|
+
instructions = instructions.replace(/## Permissions\r?\n[\s\S]*?(?=## |\r?\n---)/m, "");
|
|
17
|
+
}
|
|
18
|
+
return instructions;
|
|
15
19
|
}
|
|
16
20
|
export const TASK_SUCCESS_MARKER = "[PALMIER_TASK_SUCCESS]";
|
|
17
21
|
export const TASK_FAILURE_MARKER = "[PALMIER_TASK_FAILURE]";
|
package/dist/commands/run.js
CHANGED
|
@@ -33,7 +33,10 @@ async function invokeAgentWithRetries(ctx, invokeTask) {
|
|
|
33
33
|
publishHostEvent(ctx.nc, ctx.config.hostId, ctx.taskId, { event_type: "result-updated", run_id: ctx.runId });
|
|
34
34
|
}, 500);
|
|
35
35
|
}
|
|
36
|
-
const { command, args, stdin } = ctx.agent.getTaskRunCommandLine(invokeTask, undefined, ctx.transientPermissions);
|
|
36
|
+
const { command, args, stdin } = ctx.agent.getTaskRunCommandLine(invokeTask, undefined, ctx.task.frontmatter.yolo_mode ? "yolo" : ctx.transientPermissions);
|
|
37
|
+
const truncate = (s, max = 100) => s.length > max ? s.slice(0, max) + "…" : s;
|
|
38
|
+
const displayArgs = args.map((a) => truncate(a));
|
|
39
|
+
console.log(`[invoke] ${command} ${displayArgs.join(" ")}${stdin ? ` (stdin: ${truncate(stdin, 100)})` : ""}`);
|
|
37
40
|
const result = await spawnCommand(command, args, {
|
|
38
41
|
cwd: getRunDir(ctx.taskDir, ctx.runId),
|
|
39
42
|
env: { ...ctx.guiEnv, PALMIER_TASK_ID: ctx.task.frontmatter.id, PALMIER_RUN_DIR: getRunDir(ctx.taskDir, ctx.runId), PALMIER_HTTP_PORT: String(ctx.config.httpPort ?? 7400) },
|
|
@@ -372,7 +375,11 @@ async function requestPermission(config, task, taskDir, requiredPermissions) {
|
|
|
372
375
|
permissions: requiredPermissions,
|
|
373
376
|
}),
|
|
374
377
|
});
|
|
375
|
-
const
|
|
378
|
+
const body = await res.json();
|
|
379
|
+
const response = body.response;
|
|
380
|
+
if (!response || !["granted", "granted_all", "aborted"].includes(response)) {
|
|
381
|
+
throw new Error(`Permission request failed: ${body.error ?? `unexpected response: ${JSON.stringify(body)}`}`);
|
|
382
|
+
}
|
|
376
383
|
writeTaskStatus(taskDir, {
|
|
377
384
|
running_state: response === "aborted" ? "aborted" : "started",
|
|
378
385
|
time_stamp: Date.now(),
|
|
@@ -386,7 +393,11 @@ async function requestConfirmation(config, task, taskDir) {
|
|
|
386
393
|
headers: { "Content-Type": "application/json" },
|
|
387
394
|
body: JSON.stringify({ taskId: task.frontmatter.id, taskName: task.frontmatter.name }),
|
|
388
395
|
});
|
|
389
|
-
const
|
|
396
|
+
const body = await res.json();
|
|
397
|
+
if (typeof body.confirmed !== "boolean") {
|
|
398
|
+
throw new Error(`Confirmation request failed: ${body.error ?? `unexpected response: ${JSON.stringify(body)}`}`);
|
|
399
|
+
}
|
|
400
|
+
const { confirmed } = body;
|
|
390
401
|
writeTaskStatus(taskDir, {
|
|
391
402
|
running_state: confirmed ? "started" : "aborted",
|
|
392
403
|
time_stamp: Date.now(),
|
|
@@ -434,9 +445,15 @@ export function parsePermissions(output) {
|
|
|
434
445
|
*/
|
|
435
446
|
export function parseTaskOutcome(output) {
|
|
436
447
|
const lastChunk = output.slice(-500);
|
|
437
|
-
|
|
448
|
+
const regex = new RegExp(`^\\${TASK_FAILURE_MARKER}$|^\\${TASK_SUCCESS_MARKER}$`, "gm");
|
|
449
|
+
let last = null;
|
|
450
|
+
let match;
|
|
451
|
+
while ((match = regex.exec(lastChunk)) !== null) {
|
|
452
|
+
last = match[0];
|
|
453
|
+
}
|
|
454
|
+
if (last === TASK_FAILURE_MARKER)
|
|
438
455
|
return "failed";
|
|
439
|
-
if (
|
|
456
|
+
if (last === TASK_SUCCESS_MARKER)
|
|
440
457
|
return "finished";
|
|
441
458
|
return "finished";
|
|
442
459
|
}
|
package/dist/platform/windows.js
CHANGED
|
@@ -106,7 +106,7 @@ export class WindowsPlatform {
|
|
|
106
106
|
this.startDaemonTask();
|
|
107
107
|
process.exit(0);
|
|
108
108
|
}
|
|
109
|
-
// Kill old daemon
|
|
109
|
+
// Kill old daemon by PID
|
|
110
110
|
if (oldPid) {
|
|
111
111
|
try {
|
|
112
112
|
execFileSync("taskkill", ["/pid", oldPid, "/f", "/t"], { windowsHide: true, stdio: "pipe" });
|
|
@@ -115,6 +115,22 @@ export class WindowsPlatform {
|
|
|
115
115
|
// Process may have already exited
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
+
// Also kill any stale palmier serve processes (e.g. leftover from a previous daemon)
|
|
119
|
+
try {
|
|
120
|
+
const out = execFileSync("wmic", ["process", "where", `CommandLine like '%palmier%serve%' and ProcessId != '${process.pid}'`, "get", "ProcessId"], { encoding: "utf-8", windowsHide: true, stdio: "pipe" });
|
|
121
|
+
for (const line of out.split("\n")) {
|
|
122
|
+
const pid = line.trim();
|
|
123
|
+
if (pid && /^\d+$/.test(pid)) {
|
|
124
|
+
try {
|
|
125
|
+
execFileSync("taskkill", ["/pid", pid, "/f", "/t"], { windowsHide: true, stdio: "pipe" });
|
|
126
|
+
}
|
|
127
|
+
catch { }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// wmic may not be available on all Windows versions
|
|
133
|
+
}
|
|
118
134
|
this.startDaemonTask();
|
|
119
135
|
}
|
|
120
136
|
/** Create or update the Task Scheduler entry for the daemon. */
|
package/dist/rpc-handler.js
CHANGED
|
@@ -126,10 +126,17 @@ const activeFollowups = new Map();
|
|
|
126
126
|
export function createRpcHandler(config, nc) {
|
|
127
127
|
function flattenTask(task) {
|
|
128
128
|
const taskDir = getTaskDir(config.projectRoot, task.frontmatter.id);
|
|
129
|
+
const status = readTaskStatus(taskDir);
|
|
130
|
+
const pending = getPending(task.frontmatter.id);
|
|
129
131
|
return {
|
|
130
132
|
...task.frontmatter,
|
|
131
133
|
body: task.body,
|
|
132
|
-
status:
|
|
134
|
+
status: status ? {
|
|
135
|
+
...status,
|
|
136
|
+
...(pending?.type === "confirmation" ? { pending_confirmation: true } : {}),
|
|
137
|
+
...(pending?.type === "permission" ? { pending_permission: pending.params } : {}),
|
|
138
|
+
...(pending?.type === "input" ? { pending_input: pending.params } : {}),
|
|
139
|
+
} : undefined,
|
|
133
140
|
};
|
|
134
141
|
}
|
|
135
142
|
async function handleRpc(request) {
|
|
@@ -176,6 +183,7 @@ export function createRpcHandler(config, nc) {
|
|
|
176
183
|
triggers: params.triggers ?? [],
|
|
177
184
|
triggers_enabled: params.triggers_enabled ?? true,
|
|
178
185
|
requires_confirmation: params.requires_confirmation ?? true,
|
|
186
|
+
...(params.yolo_mode ? { yolo_mode: true } : {}),
|
|
179
187
|
...(params.command ? { command: params.command } : {}),
|
|
180
188
|
},
|
|
181
189
|
body,
|
|
@@ -204,6 +212,8 @@ export function createRpcHandler(config, nc) {
|
|
|
204
212
|
existing.frontmatter.triggers_enabled = params.triggers_enabled;
|
|
205
213
|
if (params.requires_confirmation !== undefined)
|
|
206
214
|
existing.frontmatter.requires_confirmation = params.requires_confirmation;
|
|
215
|
+
if (params.yolo_mode !== undefined)
|
|
216
|
+
existing.frontmatter.yolo_mode = params.yolo_mode || undefined;
|
|
207
217
|
if (params.command !== undefined) {
|
|
208
218
|
if (params.command) {
|
|
209
219
|
existing.frontmatter.command = params.command;
|
|
@@ -254,6 +264,7 @@ export function createRpcHandler(config, nc) {
|
|
|
254
264
|
triggers: [],
|
|
255
265
|
triggers_enabled: false,
|
|
256
266
|
requires_confirmation: params.requires_confirmation ?? false,
|
|
267
|
+
...(params.yolo_mode ? { yolo_mode: true } : {}),
|
|
257
268
|
...(params.command ? { command: params.command } : {}),
|
|
258
269
|
},
|
|
259
270
|
body: "",
|
|
@@ -317,7 +328,7 @@ export function createRpcHandler(config, nc) {
|
|
|
317
328
|
await publishHostEvent(nc, config.hostId, params.id, { event_type: "result-updated", run_id: params.run_id });
|
|
318
329
|
// Fire-and-forget: invoke agent inline as a child of the serve process
|
|
319
330
|
const followupAgent = getAgent(followupTask.frontmatter.agent);
|
|
320
|
-
const { command: cmd, args: cmdArgs, stdin } = followupAgent.getTaskRunCommandLine(followupTask, params.message, followupTask.frontmatter.permissions);
|
|
331
|
+
const { command: cmd, args: cmdArgs, stdin } = followupAgent.getTaskRunCommandLine(followupTask, params.message, followupTask.frontmatter.yolo_mode ? "yolo" : followupTask.frontmatter.permissions);
|
|
321
332
|
// Spawn directly via crossSpawn so we can track and kill the child
|
|
322
333
|
const child = crossSpawn(cmd, cmdArgs, {
|
|
323
334
|
cwd: followupRunDir,
|
|
@@ -481,8 +492,8 @@ export function createRpcHandler(config, nc) {
|
|
|
481
492
|
const reports = [];
|
|
482
493
|
const runDir = path.join(config.projectRoot, "tasks", params.id, params.run_id);
|
|
483
494
|
for (const file of params.report_files) {
|
|
484
|
-
if (!file.endsWith(".md")) {
|
|
485
|
-
reports.push({ file, error: "must end with .md" });
|
|
495
|
+
if (!file.endsWith(".md") && !file.endsWith(".txt")) {
|
|
496
|
+
reports.push({ file, error: "must end with .md or .txt" });
|
|
486
497
|
continue;
|
|
487
498
|
}
|
|
488
499
|
const basename = path.basename(file);
|
package/dist/task.d.ts
CHANGED
|
@@ -58,13 +58,23 @@ export declare function appendRunMessage(taskDir: string, runId: string, msg: Co
|
|
|
58
58
|
export declare function beginStreamingMessage(taskDir: string, runId: string, time: number): StreamingMessageWriter;
|
|
59
59
|
export declare class StreamingMessageWriter {
|
|
60
60
|
private filePath;
|
|
61
|
-
|
|
62
|
-
constructor(filePath: string, delimiter: string);
|
|
61
|
+
constructor(filePath: string);
|
|
63
62
|
/** Append a chunk of content to the current message. */
|
|
64
63
|
write(chunk: string): void;
|
|
65
|
-
/** Finalize the message. If attachments are provided, rewrites the delimiter to include them. */
|
|
64
|
+
/** Finalize the message. If attachments are provided, rewrites the last assistant delimiter to include them. */
|
|
66
65
|
end(attachments?: string[]): void;
|
|
67
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Splice a user message into a running assistant stream.
|
|
69
|
+
* Ends the current assistant block, writes the user message,
|
|
70
|
+
* then opens a new assistant block — all as direct file appends.
|
|
71
|
+
* The existing StreamingMessageWriter keeps working because its
|
|
72
|
+
* write() is just appendFileSync, so subsequent chunks land in
|
|
73
|
+
* the new assistant block.
|
|
74
|
+
*/
|
|
75
|
+
export declare function spliceUserMessage(taskDir: string, runId: string, userMsg: ConversationMessage,
|
|
76
|
+
/** Optional text to append to the current assistant block before ending it. */
|
|
77
|
+
assistantAppend?: string): void;
|
|
68
78
|
/**
|
|
69
79
|
* Read conversation messages from a run's TASKRUN.md file.
|
|
70
80
|
*/
|