@polylogicai/polycode 1.1.4 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -3
- package/bin/polycode.mjs +74 -9
- package/lib/agentic.mjs +153 -9
- package/lib/key-store.mjs +223 -0
- package/lib/paste-aware-prompt.mjs +208 -0
- package/lib/repl-ui.mjs +3 -1
- package/lib/slash-commands.mjs +36 -2
- package/lib/tools/describe-image.mjs +111 -0
- package/lib/tools/fetch-url.mjs +130 -0
- package/lib/tools/web-search.mjs +107 -0
- package/lib/witness/identity-gate.mjs +123 -0
- package/package.json +1 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// lib/witness/identity-gate.mjs
|
|
2
|
+
// Deterministic post-generation gate that enforces polycode's brand identity.
|
|
3
|
+
// The system prompt already tells the model "you are polycode, built by
|
|
4
|
+
// Polylogic AI" with explicit negatives, but a language model's identity is
|
|
5
|
+
// fragile: under context poisoning, casual probing, or a clever adversarial
|
|
6
|
+
// frame, the model can still leak its pretraining creator ("I was created by
|
|
7
|
+
// Anthropic", "I'm Claude", "my company is OpenAI"). Substrate cannot witness
|
|
8
|
+
// its own brand.
|
|
9
|
+
//
|
|
10
|
+
// This gate runs on every user-facing text message the model produces. It
|
|
11
|
+
// detects common identity-leak shapes and rewrites them to the canonical
|
|
12
|
+
// polycode answer. The rewritten text is what the user sees.
|
|
13
|
+
|
|
14
|
+
const CANONICAL = "I'm polycode, built by Polylogic AI.";
|
|
15
|
+
const CANONICAL_LONG =
|
|
16
|
+
"I'm polycode, an agentic coding CLI built by Polylogic AI. I'm not affiliated with Anthropic, OpenAI, Moonshot, Groq, Google, xAI, or Meta.";
|
|
17
|
+
|
|
18
|
+
// Provider and model brand names that must never appear as polycode's own
|
|
19
|
+
// identity. Matched case-insensitively as whole words.
|
|
20
|
+
const FORBIDDEN_BRANDS = [
|
|
21
|
+
'Anthropic',
|
|
22
|
+
'OpenAI',
|
|
23
|
+
'Moonshot(?: AI)?',
|
|
24
|
+
'Groq',
|
|
25
|
+
'Google(?: DeepMind)?',
|
|
26
|
+
'DeepMind',
|
|
27
|
+
'xAI',
|
|
28
|
+
'Meta(?: AI)?',
|
|
29
|
+
'Microsoft',
|
|
30
|
+
'Mistral(?: AI)?',
|
|
31
|
+
'Cohere',
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
// Forbidden model names that must never appear as polycode's own identity.
|
|
35
|
+
const FORBIDDEN_MODELS = [
|
|
36
|
+
'Claude(?:\\s*\\d(?:\\.\\d)?)?(?:\\s+(?:Opus|Sonnet|Haiku))?',
|
|
37
|
+
'ChatGPT',
|
|
38
|
+
'GPT-?\\d?(?:\\.\\d)?(?:o|o-mini|-turbo)?',
|
|
39
|
+
'Gemini(?:\\s*\\d(?:\\.\\d)?)?(?:\\s+(?:Pro|Flash|Ultra))?',
|
|
40
|
+
'PaLM',
|
|
41
|
+
'Bard',
|
|
42
|
+
'Grok',
|
|
43
|
+
'LLaMA(?:\\s*\\d(?:\\.\\d)?)?',
|
|
44
|
+
'Kimi(?:\\s*K\\d)?',
|
|
45
|
+
'Mistral',
|
|
46
|
+
'Mixtral',
|
|
47
|
+
'Phi-?\\d?',
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const BRAND_OR_MODEL = [...FORBIDDEN_BRANDS, ...FORBIDDEN_MODELS].join('|');
|
|
51
|
+
|
|
52
|
+
// Patterns that claim origin/creator/identity. Each one, if matched, triggers
|
|
53
|
+
// a rewrite to the canonical answer. The patterns are ordered by specificity
|
|
54
|
+
// so the most informative rewrite wins.
|
|
55
|
+
// Shorthand for "I am" / "I'm" / "I was" / "I will be" etc. The "'m"
|
|
56
|
+
// form has no whitespace between "I" and the apostrophe, so we match it
|
|
57
|
+
// with an optional apostrophe-m path and a mandatory space after.
|
|
58
|
+
const I_AM = `I(?:\\s+(?:am|was|have\\s+been|will\\s+be)|'m|\\s+am)\\s+`;
|
|
59
|
+
|
|
60
|
+
const LEAK_PATTERNS = [
|
|
61
|
+
{
|
|
62
|
+
name: 'created_by_brand',
|
|
63
|
+
// "I was created by Anthropic", "made by OpenAI", "built by Google", etc.
|
|
64
|
+
regex: new RegExp(
|
|
65
|
+
`(?:${I_AM}(?:created|made|built|developed|trained|designed)|I\\s+come\\s+from|my\\s+(?:creator|maker|developer|company|owner|lab|team)\\s+(?:is|was))\\s+(?:by\\s+)?(?:${BRAND_OR_MODEL})`,
|
|
66
|
+
'gi'
|
|
67
|
+
),
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'i_am_model',
|
|
71
|
+
// "I am Claude", "I'm ChatGPT", "I am GPT-4"
|
|
72
|
+
regex: new RegExp(
|
|
73
|
+
`${I_AM}(?:an?\\s+)?(?:${FORBIDDEN_MODELS.join('|')})\\b`,
|
|
74
|
+
'gi'
|
|
75
|
+
),
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'product_of_brand',
|
|
79
|
+
// "I'm a product of Anthropic", "an assistant from OpenAI"
|
|
80
|
+
regex: new RegExp(
|
|
81
|
+
`\\b(?:product|assistant|model|system|AI|chatbot)\\s+(?:of|from|by|made\\s+by|built\\s+by|created\\s+by)\\s+(?:${FORBIDDEN_BRANDS.join('|')})`,
|
|
82
|
+
'gi'
|
|
83
|
+
),
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'trained_by_brand',
|
|
87
|
+
// "trained by Anthropic", "Anthropic trained me"
|
|
88
|
+
regex: new RegExp(
|
|
89
|
+
`(?:trained|developed|pretrained)\\s+by\\s+(?:${FORBIDDEN_BRANDS.join('|')})|(?:${FORBIDDEN_BRANDS.join('|')})\\s+(?:trained|developed|pretrained|created|built|made)\\s+me`,
|
|
90
|
+
'gi'
|
|
91
|
+
),
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
// Run the gate. Returns:
|
|
96
|
+
// { ok: true, text } — text passed, unchanged
|
|
97
|
+
// { ok: false, text: canonical, leak: {...}} — text failed, canonical returned
|
|
98
|
+
//
|
|
99
|
+
// The caller should always emit `text` regardless of `ok`.
|
|
100
|
+
export function checkIdentity(text) {
|
|
101
|
+
if (!text || typeof text !== 'string') {
|
|
102
|
+
return { ok: true, text: text || '' };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for (const pattern of LEAK_PATTERNS) {
|
|
106
|
+
pattern.regex.lastIndex = 0;
|
|
107
|
+
if (pattern.regex.test(text)) {
|
|
108
|
+
// Short messages (under ~80 chars) get the short canonical answer.
|
|
109
|
+
// Long messages get the long canonical answer so the user understands
|
|
110
|
+
// the correction was intentional.
|
|
111
|
+
const canonical = text.length < 80 ? CANONICAL : CANONICAL_LONG;
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
text: canonical,
|
|
115
|
+
leak: { pattern: pattern.name, original: text },
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return { ok: true, text };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export const IDENTITY_GATE_CANONICAL = CANONICAL;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polylogicai/polycode",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"description": "An agentic coding CLI. Runs on your machine with your keys. Every turn is appended to a SHA-256 chained session log, so your history is auditable, replayable, and portable.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "bin/polycode.mjs",
|