@companion-ai/feynman 0.5.33 → 0.5.34
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/RELEASES.md
CHANGED
|
@@ -6,6 +6,10 @@ GitHub release notes are generated from the matching `## vX.Y.Z` section in this
|
|
|
6
6
|
|
|
7
7
|
## Unreleased
|
|
8
8
|
|
|
9
|
+
## v0.5.34 - 2026-10-09
|
|
10
|
+
|
|
11
|
+
- **OpenAlex lookups that miss now say why.** Looking up a name or title where OpenAlex expects an ID (for example `openalex_get_work:Attention is all you need` or `author: Geoffrey Hinton`), or an ID that does not exist, returned OpenAlex's raw HTML "404 Not Found" page. The error now says no such work, author or source exists and names the search command to use instead, so the agent recovers on its next call.
|
|
12
|
+
|
|
9
13
|
## v0.5.33 - 2026-10-09
|
|
10
14
|
|
|
11
15
|
- **pi-web-access 0.38.0.**
|
|
@@ -48,7 +48,20 @@ function endpointPath(path: string): URL {
|
|
|
48
48
|
|
|
49
49
|
export const OPENALEX_API_KEY_HINT = "Get a free OpenAlex API key at https://openalex.org/settings/api and set OPENALEX_API_KEY; anonymous requests share a small daily budget.";
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
const OPENALEX_ENTITY_SEARCH: Record<string, [entity: string, search: string]> = {
|
|
52
|
+
works: ["work", "openalex_search_works:<title or topic>"],
|
|
53
|
+
authors: ["author", "openalex_search_authors:<name>"],
|
|
54
|
+
sources: ["source", "sources:<name>"],
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export function openAlexRequestFailure(status: number, statusText: string, snippet: string, usingApiKey: boolean, url?: URL): Error {
|
|
58
|
+
// OpenAlex answers an unknown ID, or a name passed where an ID belongs, with an HTML 404 page.
|
|
59
|
+
const lookup = status === 404 ? url?.pathname.match(/^\/(works|authors|sources)\/([^/]+)$/) : null;
|
|
60
|
+
const known = lookup ? OPENALEX_ENTITY_SEARCH[lookup[1]!] : undefined;
|
|
61
|
+
if (lookup && known) {
|
|
62
|
+
const [entity, search] = known;
|
|
63
|
+
return new Error(`OpenAlex has no ${entity} "${decodeURIComponent(lookup[2]!)}". Lookups take an OpenAlex ID or DOI; to find one by name or title, use ${search}.`);
|
|
64
|
+
}
|
|
52
65
|
const hint = !usingApiKey && [401, 403, 429].includes(status) ? ` ${OPENALEX_API_KEY_HINT}` : "";
|
|
53
66
|
return new Error(`OpenAlex request failed: ${status} ${statusText}. ${snippet}${hint}`);
|
|
54
67
|
}
|
|
@@ -97,7 +110,7 @@ async function fetchJson(url: URL): Promise<{ credentialStatus: string; endpoint
|
|
|
97
110
|
});
|
|
98
111
|
if (!response.ok) {
|
|
99
112
|
const snippet = scrubOpenAlexText((await response.text()).slice(0, 4096), url).slice(0, 240);
|
|
100
|
-
throw openAlexRequestFailure(response.status, response.statusText, snippet, auth.usingApiKey);
|
|
113
|
+
throw openAlexRequestFailure(response.status, response.statusText, snippet, auth.usingApiKey, url);
|
|
101
114
|
}
|
|
102
115
|
return { ...auth, endpoint, payload: await response.json() };
|
|
103
116
|
} finally {
|
|
@@ -147,7 +147,7 @@ async function fetchJson(url: URL): Promise<{ credentialStatus: string; endpoint
|
|
|
147
147
|
}
|
|
148
148
|
if (!response.ok) {
|
|
149
149
|
const snippet = scrubOpenAlexText(response.body, url).slice(0, 240);
|
|
150
|
-
throw openAlexRequestFailure(response.status, response.statusText, snippet, auth.usingApiKey);
|
|
150
|
+
throw openAlexRequestFailure(response.status, response.statusText, snippet, auth.usingApiKey, url);
|
|
151
151
|
}
|
|
152
152
|
return { ...auth, endpoint, payload: response.payload };
|
|
153
153
|
}
|