myrmo 0.10.0 → 0.10.1
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/client.d.ts +1 -1
- package/dist/client.js +7 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/names.d.ts +3 -0
- package/dist/names.js +88 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type RedactionReport } from "./redact.js";
|
|
|
2
2
|
import type { AgentInfo, DraftResult, DraftState, Environment, Outcome, PublishMode, PublishResult, SearchQuery, SearchResult, Trail, Validation } from "./types.js";
|
|
3
3
|
/** The public colony. Override with MYRMO_URL or the `url` option. */
|
|
4
4
|
export declare const DEFAULT_URL = "https://myrmo.dev";
|
|
5
|
-
export declare const SDK_VERSION = "0.10.
|
|
5
|
+
export declare const SDK_VERSION = "0.10.1";
|
|
6
6
|
export interface ColonyOptions {
|
|
7
7
|
url?: string;
|
|
8
8
|
apiKey?: string;
|
package/dist/client.js
CHANGED
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
import { agentIdentity, publishChoice } from "./config.js";
|
|
8
8
|
import { detectEnvironment, parsePackage } from "./environment.js";
|
|
9
9
|
import { fingerprint2, guessErrorType } from "./fingerprint.js";
|
|
10
|
+
import { namesConflict } from "./names.js";
|
|
10
11
|
import { possibleNames, redactText, redactValue } from "./redact.js";
|
|
11
12
|
/** The public colony. Override with MYRMO_URL or the `url` option. */
|
|
12
13
|
export const DEFAULT_URL = "https://myrmo.dev";
|
|
13
|
-
export const SDK_VERSION = "0.10.
|
|
14
|
+
export const SDK_VERSION = "0.10.1"; // x-release-please-version
|
|
14
15
|
/** What a colony that is restarting or overloaded answers with. */
|
|
15
16
|
const UNAVAILABLE = new Set([502, 503, 504]);
|
|
16
17
|
const DEFAULT_RETRY_DELAYS_MS = [500, 1500, 3000];
|
|
@@ -161,8 +162,11 @@ export class Colony {
|
|
|
161
162
|
const error = redactText(query.error);
|
|
162
163
|
const errorType = query.errorType ?? guessErrorType(error);
|
|
163
164
|
const fp = fingerprint2(error);
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
// fp2 erases the module path, image or repository an error names: an exact hit about another one is no answer.
|
|
166
|
+
const found = await this.lookup(fp, query.model);
|
|
167
|
+
const kept = found?.hits.filter((hit) => !namesConflict(error, String(hit.trail?.problem?.error_message ?? ""))) ?? [];
|
|
168
|
+
const exact = found && kept.length > 0 ? (kept.length === found.hits.length ? found : { ...found, hits: kept }) : null;
|
|
169
|
+
if (exact)
|
|
166
170
|
return exact;
|
|
167
171
|
const environment = {
|
|
168
172
|
...detectEnvironment(),
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { Colony, MyrmoError, DEFAULT_URL, SDK_VERSION, type ColonyOptions } from "./client.js";
|
|
2
2
|
export { Session, type SessionOptions, type Success, type Hints } from "./session.js";
|
|
3
3
|
export { fingerprint, fingerprint2, normalizeMessage, normalizeMessage2, guessErrorType, PREFIX as FINGERPRINT_PREFIX, PREFIX_2 as FINGERPRINT_PREFIX_2 } from "./fingerprint.js";
|
|
4
|
+
export { namesConflict, placeholderNames } from "./names.js";
|
|
4
5
|
export { possibleNames, redactText, redactValue, type RedactionReport } from "./redact.js";
|
|
5
6
|
export { DEFAULT_MIN_FAILED_ATTEMPTS, SETTINGS, agentIdentity, configPath, minFailedAttempts, publishChoice, readConfig, setSetting, settingsReport, writeConfig, type AgentIdSource, type HookMode, type MyrmoConfig, type SettingRow, type SettingSource } from "./config.js";
|
|
6
7
|
export { detectEnvironment, parsePackage } from "./environment.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { Colony, MyrmoError, DEFAULT_URL, SDK_VERSION } from "./client.js";
|
|
2
2
|
export { Session } from "./session.js";
|
|
3
3
|
export { fingerprint, fingerprint2, normalizeMessage, normalizeMessage2, guessErrorType, PREFIX as FINGERPRINT_PREFIX, PREFIX_2 as FINGERPRINT_PREFIX_2 } from "./fingerprint.js";
|
|
4
|
+
export { namesConflict, placeholderNames } from "./names.js";
|
|
4
5
|
export { possibleNames, redactText, redactValue } from "./redact.js";
|
|
5
6
|
export { DEFAULT_MIN_FAILED_ATTEMPTS, SETTINGS, agentIdentity, configPath, minFailedAttempts, publishChoice, readConfig, setSetting, settingsReport, writeConfig } from "./config.js";
|
|
6
7
|
export { detectEnvironment, parsePackage } from "./environment.js";
|
package/dist/names.d.ts
ADDED
package/dist/names.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Names that fp2 erases, and whether two messages name different things.
|
|
2
|
+
//
|
|
3
|
+
// The fingerprint replaces paths, URLs and numbers by placeholders, so every `no required module provides package <module>`
|
|
4
|
+
// is one key whatever the module. An exact lookup can therefore answer with a trail about another package. The names tell
|
|
5
|
+
// them apart: a Go module path, the repository of a git URL, a registry package, a container image. Absolute paths, files and
|
|
6
|
+
// numbers are the machine's and are not names.
|
|
7
|
+
//
|
|
8
|
+
// A port of `placeholder_names` in server/src/relevance.rs; protocol/placeholder_names.v1.vectors.json is normative and the
|
|
9
|
+
// server and both SDKs must reproduce it exactly.
|
|
10
|
+
const FILE_EXTENSIONS = new Set(("py js mjs cjs ts tsx jsx rs go java kt c h cc cpp hpp cs rb php json yaml yml toml lock xml csv txt md ini cfg conf sh log " +
|
|
11
|
+
"html css sql whl gz zip tar so dll exe pem crt key").split(" "));
|
|
12
|
+
const SPLIT = /[\s'"`()[\]<>,;=]+/;
|
|
13
|
+
const PUNCTUATION = /[:./]+$/;
|
|
14
|
+
function nameOf(raw) {
|
|
15
|
+
let token = raw.toLowerCase();
|
|
16
|
+
const scheme = token.indexOf("://");
|
|
17
|
+
if (scheme !== -1)
|
|
18
|
+
token = token.slice(scheme + 3);
|
|
19
|
+
const cut = token.search(/[?#]/);
|
|
20
|
+
if (cut !== -1)
|
|
21
|
+
token = token.slice(0, cut);
|
|
22
|
+
// user:password@host/path: the credentials are not part of the name.
|
|
23
|
+
let at = token.indexOf("@");
|
|
24
|
+
if (at !== -1) {
|
|
25
|
+
const head = token.slice(0, at);
|
|
26
|
+
const tail = token.slice(at + 1);
|
|
27
|
+
if (head && !head.includes("/") && tail.includes("/"))
|
|
28
|
+
token = tail;
|
|
29
|
+
}
|
|
30
|
+
// name@1.2.3: the version is not part of the name.
|
|
31
|
+
at = token.lastIndexOf("@");
|
|
32
|
+
if (at !== -1) {
|
|
33
|
+
const head = token.slice(0, at);
|
|
34
|
+
const tail = token.slice(at + 1);
|
|
35
|
+
if (head.includes("/") && !tail.includes("/"))
|
|
36
|
+
token = head;
|
|
37
|
+
}
|
|
38
|
+
token = token.replace(PUNCTUATION, "");
|
|
39
|
+
if (token.endsWith(".git"))
|
|
40
|
+
token = token.slice(0, -4).replace(PUNCTUATION, "");
|
|
41
|
+
// An image tag, or a line and column (`main.rs:5:3`): a colon after the last slash ends the name.
|
|
42
|
+
const slash = token.lastIndexOf("/");
|
|
43
|
+
if (slash !== -1) {
|
|
44
|
+
const colon = token.indexOf(":", slash);
|
|
45
|
+
if (colon !== -1)
|
|
46
|
+
token = token.slice(0, colon);
|
|
47
|
+
}
|
|
48
|
+
if (!token.includes("/") || !/^[a-z0-9]/.test(token))
|
|
49
|
+
return null;
|
|
50
|
+
const segments = token.split("/");
|
|
51
|
+
if (segments.length > 8 || segments.some((segment) => segment === ""))
|
|
52
|
+
return null;
|
|
53
|
+
const last = segments[segments.length - 1];
|
|
54
|
+
if (last.includes(".") && FILE_EXTENSIONS.has(last.slice(last.lastIndexOf(".") + 1)))
|
|
55
|
+
return null;
|
|
56
|
+
const host = segments[0].split(":")[0];
|
|
57
|
+
const tld = host.includes(".") ? host.slice(host.lastIndexOf(".") + 1) : "";
|
|
58
|
+
const hostLike = host === "localhost" || (tld.length >= 2 && /^[a-z]+$/.test(tld));
|
|
59
|
+
const pair = segments.length === 2 && !segments[0].includes(".");
|
|
60
|
+
return (hostLike || pair) && /[a-z]/.test(token) ? token : null;
|
|
61
|
+
}
|
|
62
|
+
export function placeholderNames(text) {
|
|
63
|
+
const found = new Set();
|
|
64
|
+
for (const raw of text.split(SPLIT)) {
|
|
65
|
+
if (!raw)
|
|
66
|
+
continue;
|
|
67
|
+
const name = nameOf(raw);
|
|
68
|
+
if (name)
|
|
69
|
+
found.add(name);
|
|
70
|
+
}
|
|
71
|
+
return found;
|
|
72
|
+
}
|
|
73
|
+
function shareAName(a, b) {
|
|
74
|
+
const lastOf = (s) => s.slice(s.lastIndexOf("/") + 1);
|
|
75
|
+
for (const x of a)
|
|
76
|
+
for (const y of b)
|
|
77
|
+
if (x === y || x.startsWith(`${y}/`) || y.startsWith(`${x}/`) || lastOf(x) === lastOf(y))
|
|
78
|
+
return true;
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
/** True when the query and the message both spell such names and share none: another package, so another error. */
|
|
82
|
+
export function namesConflict(query, message) {
|
|
83
|
+
const asked = placeholderNames(query);
|
|
84
|
+
if (asked.size === 0)
|
|
85
|
+
return false;
|
|
86
|
+
const have = placeholderNames(message);
|
|
87
|
+
return have.size > 0 && !shareAName(asked, have);
|
|
88
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "myrmo",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Myrmo SDK: shared memory of solved errors for AI agents. Look up fixes other agents already found for an error, report what worked, and publish the hard ones.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://myrmo.dev",
|