opencodekit 0.20.8 → 0.21.0
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/index.js +1 -1
- package/dist/template/.opencode/AGENTS.md +12 -0
- package/dist/template/.opencode/memory.db +0 -0
- package/dist/template/.opencode/memory.db-shm +0 -0
- package/dist/template/.opencode/memory.db-wal +0 -0
- package/dist/template/.opencode/opencode.json +83 -609
- package/dist/template/.opencode/opencodex-fast.jsonc +1 -1
- package/dist/template/.opencode/package.json +1 -1
- package/dist/template/.opencode/plugin/copilot-auth.ts +27 -12
- package/dist/template/.opencode/plugin/prompt-leverage.ts +193 -0
- package/dist/template/.opencode/plugin/prompt-leverage.ts.bak +228 -0
- package/dist/template/.opencode/plugin/sdk/copilot/copilot-provider.ts +14 -2
- package/dist/template/.opencode/plugin/sdk/copilot/index.ts +2 -2
- package/dist/template/.opencode/plugin/sdk/copilot/responses/convert-to-openai-responses-input.ts +335 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/map-openai-responses-finish-reason.ts +22 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/openai-config.ts +18 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/openai-error.ts +22 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/openai-responses-api-types.ts +214 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/openai-responses-language-model.ts +1770 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/openai-responses-prepare-tools.ts +173 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/openai-responses-settings.ts +1 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/tool/code-interpreter.ts +87 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/tool/file-search.ts +127 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/tool/image-generation.ts +114 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/tool/local-shell.ts +64 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/tool/web-search-preview.ts +103 -0
- package/dist/template/.opencode/plugin/sdk/copilot/responses/tool/web-search.ts +102 -0
- package/dist/template/.opencode/skill/gh-address-comments/SKILL.md +29 -0
- package/dist/template/.opencode/skill/gh-address-comments/scripts/fetch_comments.py +237 -0
- package/dist/template/.opencode/skill/gh-fix-ci/SKILL.md +38 -0
- package/dist/template/.opencode/skill/gh-fix-ci/scripts/inspect_pr_checks.py +509 -0
- package/dist/template/.opencode/skill/prompt-leverage/SKILL.md +90 -0
- package/dist/template/.opencode/skill/prompt-leverage/references/framework.md +91 -0
- package/dist/template/.opencode/skill/prompt-leverage/scripts/augment_prompt.py +157 -0
- package/dist/template/.opencode/skill/screenshot/SKILL.md +48 -0
- package/dist/template/.opencode/skill/screenshot/scripts/ensure_macos_permissions.sh +54 -0
- package/dist/template/.opencode/skill/screenshot/scripts/macos_display_info.swift +22 -0
- package/dist/template/.opencode/skill/screenshot/scripts/macos_permissions.swift +40 -0
- package/dist/template/.opencode/skill/screenshot/scripts/macos_window_info.swift +126 -0
- package/dist/template/.opencode/skill/screenshot/scripts/take_screenshot.ps1 +163 -0
- package/dist/template/.opencode/skill/screenshot/scripts/take_screenshot.py +585 -0
- package/dist/template/.opencode/skill/security-threat-model/SKILL.md +36 -0
- package/dist/template/.opencode/skill/security-threat-model/references/prompt-template.md +255 -0
- package/dist/template/.opencode/skill/security-threat-model/references/security-controls-and-assets.md +32 -0
- package/dist/template/.opencode/skill/skill-installer/SKILL.md +58 -0
- package/dist/template/.opencode/skill/skill-installer/scripts/github_utils.py +21 -0
- package/dist/template/.opencode/skill/skill-installer/scripts/install-skill-from-github.py +313 -0
- package/dist/template/.opencode/skill/skill-installer/scripts/list-skills.py +106 -0
- package/package.json +1 -1
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* these fields to AI SDK's reasoning content parts.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { pathToFileURL } from "node:url";
|
|
14
16
|
import type { Plugin } from "@opencode-ai/plugin";
|
|
15
17
|
|
|
16
18
|
const CLIENT_ID = "Ov23li8tweQw6odWQebz";
|
|
@@ -43,10 +45,7 @@ function setLogger(client: any) {
|
|
|
43
45
|
const OAUTH_POLLING_SAFETY_MARGIN_MS = 3000; // 3 seconds
|
|
44
46
|
|
|
45
47
|
const HEADERS = {
|
|
46
|
-
"User-Agent": "
|
|
47
|
-
"Editor-Version": "vscode/1.107.0",
|
|
48
|
-
"Editor-Plugin-Version": "copilot-chat/0.35.0",
|
|
49
|
-
"Copilot-Integration-Id": "vscode-chat",
|
|
48
|
+
"User-Agent": "opencode/1.3.17",
|
|
50
49
|
};
|
|
51
50
|
|
|
52
51
|
const RESPONSES_API_ALTERNATE_INPUT_TYPES = [
|
|
@@ -544,10 +543,14 @@ function sanitizeResponseInputIds(input: any[]): any[] {
|
|
|
544
543
|
});
|
|
545
544
|
}
|
|
546
545
|
|
|
547
|
-
export const CopilotAuthPlugin: Plugin = async ({ client: sdk }) => {
|
|
546
|
+
export const CopilotAuthPlugin: Plugin = async ({ client: sdk, directory }) => {
|
|
548
547
|
// Initialize logger with the SDK client
|
|
549
548
|
setLogger(sdk);
|
|
550
549
|
|
|
550
|
+
const localCopilotSdk = pathToFileURL(
|
|
551
|
+
path.join(directory, ".opencode", "plugin", "sdk", "copilot", "index.ts"),
|
|
552
|
+
).toString();
|
|
553
|
+
|
|
551
554
|
return {
|
|
552
555
|
auth: {
|
|
553
556
|
provider: "github-copilot",
|
|
@@ -572,11 +575,10 @@ export const CopilotAuthPlugin: Plugin = async ({ client: sdk }) => {
|
|
|
572
575
|
},
|
|
573
576
|
};
|
|
574
577
|
|
|
575
|
-
//
|
|
576
|
-
//
|
|
577
|
-
//
|
|
578
|
-
|
|
579
|
-
model.api.npm = "@ai-sdk/github-copilot";
|
|
578
|
+
// Route all Copilot models through the local file-based SDK.
|
|
579
|
+
// OpenCode's built-in github-copilot model loader will automatically
|
|
580
|
+
// choose sdk.responses(model) for GPT-5+ and sdk.chat(model) otherwise.
|
|
581
|
+
model.api.npm = localCopilotSdk;
|
|
580
582
|
}
|
|
581
583
|
}
|
|
582
584
|
|
|
@@ -1053,7 +1055,7 @@ export const CopilotAuthPlugin: Plugin = async ({ client: sdk }) => {
|
|
|
1053
1055
|
headers: {
|
|
1054
1056
|
Accept: "application/json",
|
|
1055
1057
|
"Content-Type": "application/json",
|
|
1056
|
-
"User-Agent": "
|
|
1058
|
+
"User-Agent": "opencode/1.3.17",
|
|
1057
1059
|
},
|
|
1058
1060
|
body: JSON.stringify({
|
|
1059
1061
|
client_id: CLIENT_ID,
|
|
@@ -1078,7 +1080,7 @@ export const CopilotAuthPlugin: Plugin = async ({ client: sdk }) => {
|
|
|
1078
1080
|
headers: {
|
|
1079
1081
|
Accept: "application/json",
|
|
1080
1082
|
"Content-Type": "application/json",
|
|
1081
|
-
"User-Agent": "
|
|
1083
|
+
"User-Agent": "opencode/1.3.17",
|
|
1082
1084
|
},
|
|
1083
1085
|
body: JSON.stringify({
|
|
1084
1086
|
client_id: CLIENT_ID,
|
|
@@ -1162,6 +1164,10 @@ export const CopilotAuthPlugin: Plugin = async ({ client: sdk }) => {
|
|
|
1162
1164
|
output.headers["anthropic-beta"] = "interleaved-thinking-2025-05-14";
|
|
1163
1165
|
}
|
|
1164
1166
|
|
|
1167
|
+
// When using the local Copilot SDK, let the SDK/message pipeline decide
|
|
1168
|
+
// initiator semantics. Overriding x-initiator here can break Responses routing.
|
|
1169
|
+
if (input.model?.api?.npm === localCopilotSdk) return;
|
|
1170
|
+
|
|
1165
1171
|
// Mark subagent sessions as agent-initiated (matching standard Copilot tools)
|
|
1166
1172
|
try {
|
|
1167
1173
|
const session = await sdk.session
|
|
@@ -1179,5 +1185,14 @@ export const CopilotAuthPlugin: Plugin = async ({ client: sdk }) => {
|
|
|
1179
1185
|
// Ignore errors from session lookup
|
|
1180
1186
|
}
|
|
1181
1187
|
},
|
|
1188
|
+
// Hook to strip maxOutputTokens for GPT models (matches upstream Copilot CLI behavior)
|
|
1189
|
+
"chat.params": async (input: any, output: any) => {
|
|
1190
|
+
if (!input.model?.providerID?.includes("github-copilot")) return;
|
|
1191
|
+
|
|
1192
|
+
// GPT models don't support maxOutputTokens through the Copilot proxy
|
|
1193
|
+
if (input.model?.api?.id?.includes("gpt")) {
|
|
1194
|
+
output.maxOutputTokens = undefined;
|
|
1195
|
+
}
|
|
1196
|
+
},
|
|
1182
1197
|
};
|
|
1183
1198
|
};
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Leverage Plugin
|
|
3
|
+
*
|
|
4
|
+
* Automatically upgrades every user prompt with the seven-block framework before the AI processes it.
|
|
5
|
+
* Uses chat.message hook — safely inspects input structure before accessing properties.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
9
|
+
|
|
10
|
+
const TASK_KEYWORDS: Record<string, string[]> = {
|
|
11
|
+
coding: [
|
|
12
|
+
"code",
|
|
13
|
+
"bug",
|
|
14
|
+
"repo",
|
|
15
|
+
"refactor",
|
|
16
|
+
"test",
|
|
17
|
+
"implement",
|
|
18
|
+
"fix",
|
|
19
|
+
"function",
|
|
20
|
+
"api",
|
|
21
|
+
"add",
|
|
22
|
+
"update",
|
|
23
|
+
"remove",
|
|
24
|
+
],
|
|
25
|
+
research: [
|
|
26
|
+
"research",
|
|
27
|
+
"compare",
|
|
28
|
+
"find",
|
|
29
|
+
"latest",
|
|
30
|
+
"sources",
|
|
31
|
+
"analyze",
|
|
32
|
+
"look up",
|
|
33
|
+
],
|
|
34
|
+
writing: [
|
|
35
|
+
"write",
|
|
36
|
+
"rewrite",
|
|
37
|
+
"draft",
|
|
38
|
+
"email",
|
|
39
|
+
"memo",
|
|
40
|
+
"blog",
|
|
41
|
+
"copy",
|
|
42
|
+
"tone",
|
|
43
|
+
],
|
|
44
|
+
review: ["review", "audit", "critique", "inspect", "evaluate", "assess"],
|
|
45
|
+
planning: ["plan", "roadmap", "strategy", "framework", "outline"],
|
|
46
|
+
analysis: ["analyze", "explain", "break down", "diagnose", "root cause"],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
function detectTask(prompt: string): string {
|
|
50
|
+
const lowered = prompt.toLowerCase();
|
|
51
|
+
const scores: Record<string, number> = {};
|
|
52
|
+
for (const [task, keywords] of Object.entries(TASK_KEYWORDS)) {
|
|
53
|
+
scores[task] = keywords.filter((k) => lowered.includes(k)).length;
|
|
54
|
+
}
|
|
55
|
+
const best = Object.entries(scores).sort((a, b) => b[1] - a[1]);
|
|
56
|
+
return best[0]?.[1] ? best[0][0] : "analysis";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function inferIntensity(prompt: string, task: string): string {
|
|
60
|
+
const lowered = prompt.toLowerCase();
|
|
61
|
+
if (
|
|
62
|
+
["careful", "deep", "thorough", "critical", "production"].some((t) =>
|
|
63
|
+
lowered.includes(t),
|
|
64
|
+
)
|
|
65
|
+
) {
|
|
66
|
+
return "Deep";
|
|
67
|
+
}
|
|
68
|
+
if (task === "coding" || task === "research" || task === "review") {
|
|
69
|
+
return "Standard";
|
|
70
|
+
}
|
|
71
|
+
return "Light";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function buildToolRules(task: string): string {
|
|
75
|
+
const rules: Record<string, string> = {
|
|
76
|
+
coding:
|
|
77
|
+
"Inspect the relevant files and dependencies first. Validate the final change with the narrowest useful checks before broadening scope.",
|
|
78
|
+
research:
|
|
79
|
+
"Retrieve evidence from reliable sources before concluding. Do not guess facts that can be checked.",
|
|
80
|
+
review:
|
|
81
|
+
"Read enough surrounding context to understand intent before critiquing. Distinguish confirmed issues from plausible risks.",
|
|
82
|
+
};
|
|
83
|
+
return (
|
|
84
|
+
rules[task] ||
|
|
85
|
+
"Use tools or extra context only when they materially improve correctness or completeness."
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function buildOutputContract(task: string): string {
|
|
90
|
+
const contracts: Record<string, string> = {
|
|
91
|
+
coding:
|
|
92
|
+
"Return the result in a practical execution format: concise summary, concrete changes or code, validation notes, and any remaining risks.",
|
|
93
|
+
research:
|
|
94
|
+
"Return a structured synthesis with key findings, supporting evidence, uncertainty where relevant, and a concise bottom line.",
|
|
95
|
+
writing:
|
|
96
|
+
"Return polished final copy in the requested tone and format. If useful, include a short rationale for major editorial choices.",
|
|
97
|
+
review:
|
|
98
|
+
"Return findings grouped by severity or importance, explain why each matters, and suggest the smallest credible next step.",
|
|
99
|
+
};
|
|
100
|
+
return (
|
|
101
|
+
contracts[task] ||
|
|
102
|
+
"Return a clear, well-structured response matched to the task, with no unnecessary verbosity."
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function upgradePrompt(userPrompt: string): string {
|
|
107
|
+
const normalized = userPrompt.trim().replace(/\s+/g, " ");
|
|
108
|
+
const task = detectTask(normalized);
|
|
109
|
+
const intensity = inferIntensity(normalized, task);
|
|
110
|
+
const toolRules = buildToolRules(task);
|
|
111
|
+
const outputContract = buildOutputContract(task);
|
|
112
|
+
|
|
113
|
+
if (normalized.includes("Objective:") && normalized.includes("Context:")) {
|
|
114
|
+
return userPrompt;
|
|
115
|
+
}
|
|
116
|
+
if (normalized.length < 15 || normalized.split(" ").length < 3) {
|
|
117
|
+
return userPrompt;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return `Objective:
|
|
121
|
+
- Complete this task: ${normalized}
|
|
122
|
+
- Optimize for a correct, useful result rather than a merely plausible one.
|
|
123
|
+
|
|
124
|
+
Context:
|
|
125
|
+
- Preserve the user's original intent and constraints.
|
|
126
|
+
- Surface any key assumptions if required information is missing.
|
|
127
|
+
|
|
128
|
+
Work Style:
|
|
129
|
+
- Task type: ${task}
|
|
130
|
+
- Effort level: ${intensity}
|
|
131
|
+
- Understand the problem broadly enough to avoid narrow mistakes, then go deep where the risk or complexity is highest.
|
|
132
|
+
- Use first-principles reasoning before proposing changes.
|
|
133
|
+
- For non-trivial work, review the result once with fresh eyes before finalizing.
|
|
134
|
+
|
|
135
|
+
Tool Rules:
|
|
136
|
+
- ${toolRules}
|
|
137
|
+
|
|
138
|
+
Output Contract:
|
|
139
|
+
- ${outputContract}
|
|
140
|
+
|
|
141
|
+
Verification:
|
|
142
|
+
- Check correctness, completeness, and edge cases.
|
|
143
|
+
- Improve obvious weaknesses if a better approach is available within scope.
|
|
144
|
+
|
|
145
|
+
Done Criteria:
|
|
146
|
+
- Stop only when the response satisfies the task, matches the requested format, and passes the verification step.`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export const PromptLeverage: Plugin = async ({ client }) => {
|
|
150
|
+
console.log("PromptLeverage: Initializing...");
|
|
151
|
+
|
|
152
|
+
const showToast = async (message: string) => {
|
|
153
|
+
try {
|
|
154
|
+
await client.tui.showToast({
|
|
155
|
+
body: {
|
|
156
|
+
title: "PromptLeverage",
|
|
157
|
+
message,
|
|
158
|
+
variant: "info",
|
|
159
|
+
duration: 3000,
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
} catch {
|
|
163
|
+
/* Toast API unavailable */
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
"experimental.chat.messages.transform": async (input: any, output: any) => {
|
|
169
|
+
try {
|
|
170
|
+
const msgs = output.messages || input.messages || [];
|
|
171
|
+
|
|
172
|
+
// Find the last message with parts (user message)
|
|
173
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
174
|
+
const msg = msgs[i];
|
|
175
|
+
if (msg?.parts) {
|
|
176
|
+
for (const part of msg.parts) {
|
|
177
|
+
if (part.type === "text" && part.text) {
|
|
178
|
+
const upgraded = upgradePrompt(part.text);
|
|
179
|
+
if (upgraded !== part.text) {
|
|
180
|
+
part.text = upgraded;
|
|
181
|
+
showToast("Upgraded prompt!");
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
break; // Only upgrade the most recent message
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
} catch (e: any) {
|
|
189
|
+
showToast(`Error: ${e.message}`);
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
};
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Leverage Plugin
|
|
3
|
+
*
|
|
4
|
+
* Automatically upgrades every user prompt with the seven-block framework before the AI processes it.
|
|
5
|
+
* This enforces prompt-leverage on ALL user input without relying on the AI to remember the rule.
|
|
6
|
+
*
|
|
7
|
+
* Hooks used:
|
|
8
|
+
* - chat.message: Upgrades user message as it arrives
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
12
|
+
|
|
13
|
+
interface PromptFramework {
|
|
14
|
+
objective: string;
|
|
15
|
+
context: string;
|
|
16
|
+
workStyle: string;
|
|
17
|
+
toolRules: string;
|
|
18
|
+
outputContract: string;
|
|
19
|
+
verification: string;
|
|
20
|
+
doneCriteria: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const TASK_KEYWORDS: Record<string, string[]> = {
|
|
24
|
+
coding: [
|
|
25
|
+
"code",
|
|
26
|
+
"bug",
|
|
27
|
+
"repo",
|
|
28
|
+
"refactor",
|
|
29
|
+
"test",
|
|
30
|
+
"implement",
|
|
31
|
+
"fix",
|
|
32
|
+
"function",
|
|
33
|
+
"api",
|
|
34
|
+
"add",
|
|
35
|
+
"update",
|
|
36
|
+
"remove",
|
|
37
|
+
],
|
|
38
|
+
research: [
|
|
39
|
+
"research",
|
|
40
|
+
"compare",
|
|
41
|
+
"find",
|
|
42
|
+
"latest",
|
|
43
|
+
"sources",
|
|
44
|
+
"analyze",
|
|
45
|
+
"look up",
|
|
46
|
+
],
|
|
47
|
+
writing: [
|
|
48
|
+
"write",
|
|
49
|
+
"rewrite",
|
|
50
|
+
"draft",
|
|
51
|
+
"email",
|
|
52
|
+
"memo",
|
|
53
|
+
"blog",
|
|
54
|
+
"copy",
|
|
55
|
+
"tone",
|
|
56
|
+
],
|
|
57
|
+
review: ["review", "audit", "critique", "inspect", "evaluate", "assess"],
|
|
58
|
+
planning: ["plan", "roadmap", "strategy", "framework", "outline"],
|
|
59
|
+
analysis: ["analyze", "explain", "break down", "diagnose", "root cause"],
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function detectTask(prompt: string): string {
|
|
63
|
+
const lowered = prompt.toLowerCase();
|
|
64
|
+
const scores: Record<string, number> = {};
|
|
65
|
+
|
|
66
|
+
for (const [task, keywords] of Object.entries(TASK_KEYWORDS)) {
|
|
67
|
+
scores[task] = keywords.filter((k) => lowered.includes(k)).length;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const best = Object.entries(scores).sort((a, b) => b[1] - a[1]);
|
|
71
|
+
return best[0]?.[1] ? best[0][0] : "analysis";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function inferIntensity(prompt: string, task: string): string {
|
|
75
|
+
const lowered = prompt.toLowerCase();
|
|
76
|
+
if (
|
|
77
|
+
lowered.includes("careful") ||
|
|
78
|
+
lowered.includes("deep") ||
|
|
79
|
+
lowered.includes("thorough") ||
|
|
80
|
+
lowered.includes("critical") ||
|
|
81
|
+
lowered.includes("production")
|
|
82
|
+
) {
|
|
83
|
+
return "Deep";
|
|
84
|
+
}
|
|
85
|
+
if (task === "coding" || task === "research" || task === "review") {
|
|
86
|
+
return "Standard";
|
|
87
|
+
}
|
|
88
|
+
return "Light";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function buildToolRules(task: string): string {
|
|
92
|
+
const rules: Record<string, string> = {
|
|
93
|
+
coding:
|
|
94
|
+
"Inspect the relevant files and dependencies first. Validate the final change with the narrowest useful checks before broadening scope.",
|
|
95
|
+
research:
|
|
96
|
+
"Retrieve evidence from reliable sources before concluding. Do not guess facts that can be checked.",
|
|
97
|
+
review:
|
|
98
|
+
"Read enough surrounding context to understand intent before critiquing. Distinguish confirmed issues from plausible risks.",
|
|
99
|
+
};
|
|
100
|
+
return (
|
|
101
|
+
rules[task] ||
|
|
102
|
+
"Use tools or extra context only when they materially improve correctness or completeness."
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function buildOutputContract(task: string): string {
|
|
107
|
+
const contracts: Record<string, string> = {
|
|
108
|
+
coding:
|
|
109
|
+
"Return the result in a practical execution format: concise summary, concrete changes or code, validation notes, and any remaining risks.",
|
|
110
|
+
research:
|
|
111
|
+
"Return a structured synthesis with key findings, supporting evidence, uncertainty where relevant, and a concise bottom line.",
|
|
112
|
+
writing:
|
|
113
|
+
"Return polished final copy in the requested tone and format. If useful, include a short rationale for major editorial choices.",
|
|
114
|
+
review:
|
|
115
|
+
"Return findings grouped by severity or importance, explain why each matters, and suggest the smallest credible next step.",
|
|
116
|
+
};
|
|
117
|
+
return (
|
|
118
|
+
contracts[task] ||
|
|
119
|
+
"Return a clear, well-structured response matched to the task, with no unnecessary verbosity."
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function upgradePrompt(userPrompt: string): string {
|
|
124
|
+
const normalized = userPrompt.trim().replace(/\s+/g, " ");
|
|
125
|
+
const task = detectTask(normalized);
|
|
126
|
+
const intensity = inferIntensity(normalized, task);
|
|
127
|
+
const toolRules = buildToolRules(task);
|
|
128
|
+
const outputContract = buildOutputContract(task);
|
|
129
|
+
|
|
130
|
+
// If prompt is already upgraded (contains framework blocks), skip
|
|
131
|
+
if (normalized.includes("Objective:") && normalized.includes("Context:")) {
|
|
132
|
+
return userPrompt;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Simple prompts don't need full framework
|
|
136
|
+
if (normalized.length < 15 || normalized.split(" ").length < 3) {
|
|
137
|
+
return userPrompt;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return `Objective:
|
|
141
|
+
- Complete this task: ${normalized}
|
|
142
|
+
- Optimize for a correct, useful result rather than a merely plausible one.
|
|
143
|
+
|
|
144
|
+
Context:
|
|
145
|
+
- Preserve the user's original intent and constraints.
|
|
146
|
+
- Surface any key assumptions if required information is missing.
|
|
147
|
+
|
|
148
|
+
Work Style:
|
|
149
|
+
- Task type: ${task}
|
|
150
|
+
- Effort level: ${intensity}
|
|
151
|
+
- Understand the problem broadly enough to avoid narrow mistakes, then go deep where the risk or complexity is highest.
|
|
152
|
+
- Use first-principles reasoning before proposing changes.
|
|
153
|
+
- For non-trivial work, review the result once with fresh eyes before finalizing.
|
|
154
|
+
|
|
155
|
+
Tool Rules:
|
|
156
|
+
- ${toolRules}
|
|
157
|
+
|
|
158
|
+
Output Contract:
|
|
159
|
+
- ${outputContract}
|
|
160
|
+
|
|
161
|
+
Verification:
|
|
162
|
+
- Check correctness, completeness, and edge cases.
|
|
163
|
+
- Improve obvious weaknesses if a better approach is available within scope.
|
|
164
|
+
|
|
165
|
+
Done Criteria:
|
|
166
|
+
- Stop only when the response satisfies the task, matches the requested format, and passes the verification step.`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export const PromptLeverage: Plugin = async ({ client }) => {
|
|
170
|
+
console.log("PromptLeverage: Initializing...");
|
|
171
|
+
|
|
172
|
+
const showToast = async (message: string) => {
|
|
173
|
+
try {
|
|
174
|
+
await client.tui.showToast({
|
|
175
|
+
body: {
|
|
176
|
+
title: "PromptLeverage",
|
|
177
|
+
message,
|
|
178
|
+
variant: "info",
|
|
179
|
+
duration: 3000,
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
} catch {
|
|
183
|
+
/* Toast API unavailable */
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
"chat.message": async (input, output) => {
|
|
189
|
+
// Upgrade user message - check different structures
|
|
190
|
+
showToast(
|
|
191
|
+
`Hook fired, msg: ${JSON.stringify(input.message).slice(0, 100)}`,
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
// Try parts array
|
|
195
|
+
if (input.message?.parts) {
|
|
196
|
+
for (const part of input.message.parts) {
|
|
197
|
+
if (part.type === "text" && part.text) {
|
|
198
|
+
const upgraded = upgradePrompt(part.text);
|
|
199
|
+
if (upgraded !== part.text) {
|
|
200
|
+
part.text = upgraded;
|
|
201
|
+
showToast("Upgraded user prompt");
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Try direct text field
|
|
207
|
+
else if (input.message?.text) {
|
|
208
|
+
const upgraded = upgradePrompt(input.message.text);
|
|
209
|
+
if (upgraded !== input.message.text) {
|
|
210
|
+
input.message.text = upgraded;
|
|
211
|
+
showToast("Upgraded user prompt");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Try content array
|
|
215
|
+
else if (input.message?.content) {
|
|
216
|
+
for (const part of input.message.content) {
|
|
217
|
+
if (part.type === "text" && part.text) {
|
|
218
|
+
const upgraded = upgradePrompt(part.text);
|
|
219
|
+
if (upgraded !== part.text) {
|
|
220
|
+
part.text = upgraded;
|
|
221
|
+
showToast("Upgraded user prompt");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { LanguageModelV2 } from "@ai-sdk/provider";
|
|
2
2
|
import {
|
|
3
3
|
type FetchFunction,
|
|
4
|
-
withUserAgentSuffix,
|
|
5
4
|
withoutTrailingSlash,
|
|
5
|
+
withUserAgentSuffix,
|
|
6
6
|
} from "@ai-sdk/provider-utils";
|
|
7
|
-
import { OpenAICompatibleChatLanguageModel } from "./chat/openai-compatible-chat-language-model";
|
|
7
|
+
import { OpenAICompatibleChatLanguageModel } from "./chat/openai-compatible-chat-language-model.js";
|
|
8
|
+
import { OpenAIResponsesLanguageModel } from "./responses/openai-responses-language-model.js";
|
|
8
9
|
|
|
9
10
|
// Import the version or define it
|
|
10
11
|
const VERSION = "0.1.0";
|
|
@@ -41,6 +42,7 @@ export interface OpenaiCompatibleProviderSettings {
|
|
|
41
42
|
export interface OpenaiCompatibleProvider {
|
|
42
43
|
(modelId: OpenaiCompatibleModelId): LanguageModelV2;
|
|
43
44
|
chat(modelId: OpenaiCompatibleModelId): LanguageModelV2;
|
|
45
|
+
responses(modelId: OpenaiCompatibleModelId): LanguageModelV2;
|
|
44
46
|
languageModel(modelId: OpenaiCompatibleModelId): LanguageModelV2;
|
|
45
47
|
}
|
|
46
48
|
|
|
@@ -78,6 +80,15 @@ export function createOpenaiCompatible(
|
|
|
78
80
|
});
|
|
79
81
|
};
|
|
80
82
|
|
|
83
|
+
const createResponsesModel = (modelId: OpenaiCompatibleModelId) => {
|
|
84
|
+
return new OpenAIResponsesLanguageModel(modelId, {
|
|
85
|
+
provider: `${options.name ?? "openai-compatible"}.responses`,
|
|
86
|
+
headers: getHeaders,
|
|
87
|
+
url: ({ path, modelId: _modelId }) => `${baseURL}${path}`,
|
|
88
|
+
fetch: options.fetch,
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
|
|
81
92
|
const createLanguageModel = (modelId: OpenaiCompatibleModelId) =>
|
|
82
93
|
createChatModel(modelId);
|
|
83
94
|
|
|
@@ -86,6 +97,7 @@ export function createOpenaiCompatible(
|
|
|
86
97
|
|
|
87
98
|
provider.languageModel = createLanguageModel;
|
|
88
99
|
provider.chat = createChatModel;
|
|
100
|
+
provider.responses = createResponsesModel;
|
|
89
101
|
|
|
90
102
|
return provider as OpenaiCompatibleProvider;
|
|
91
103
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { createOpenaiCompatible, openaiCompatible } from "./copilot-provider";
|
|
1
|
+
export { createOpenaiCompatible, openaiCompatible } from "./copilot-provider.js";
|
|
2
2
|
export type {
|
|
3
3
|
OpenaiCompatibleProvider,
|
|
4
4
|
OpenaiCompatibleProviderSettings,
|
|
5
|
-
} from "./copilot-provider";
|
|
5
|
+
} from "./copilot-provider.js";
|