@nevescloud/pip 3.8.1 → 3.8.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nevescloud/pip",
3
- "version": "3.8.1",
3
+ "version": "3.8.3",
4
4
  "description": "Floating assistant bubble + panel + chat runtime. ESM, no build.",
5
5
  "type": "module",
6
6
  "main": "pip-core.esm.js",
@@ -23,8 +23,14 @@ export function anthropic({
23
23
  effort,
24
24
  cacheControl,
25
25
  extraHeaders = {},
26
+ // When true, the host is routing through a proxy/bridge that injects
27
+ // auth + version headers server-side. The provider then sends only
28
+ // content-type; this avoids the CORS preflight burden of x-api-key /
29
+ // anthropic-version / anthropic-dangerous-direct-browser-access on
30
+ // proxies that haven't allowlisted those headers.
31
+ proxied = false,
26
32
  } = {}) {
27
- if (!apiKey) throw new Error('anthropic provider: apiKey is required');
33
+ if (!proxied && !apiKey) throw new Error('anthropic provider: apiKey is required (or set proxied: true when routing through a bridge that injects auth)');
28
34
 
29
35
  return async function* anthropicProvider({ messages, tools, system, signal }) {
30
36
  const body = {
@@ -45,15 +51,16 @@ export function anthropic({
45
51
  if (effort) body.output_config = { effort };
46
52
  if (cacheControl) body.cache_control = { type: cacheControl };
47
53
 
54
+ const headers = { 'content-type': 'application/json', ...extraHeaders };
55
+ if (!proxied) {
56
+ headers['x-api-key'] = apiKey;
57
+ headers['anthropic-version'] = ANTHROPIC_VERSION;
58
+ headers['anthropic-dangerous-direct-browser-access'] = 'true';
59
+ }
60
+
48
61
  const res = await fetch(`${baseUrl}/v1/messages`, {
49
62
  method: 'POST',
50
- headers: {
51
- 'content-type': 'application/json',
52
- 'x-api-key': apiKey,
53
- 'anthropic-version': ANTHROPIC_VERSION,
54
- 'anthropic-dangerous-direct-browser-access': 'true',
55
- ...extraHeaders,
56
- },
63
+ headers,
57
64
  body: JSON.stringify(body),
58
65
  signal,
59
66
  });
package/runtime.esm.js CHANGED
@@ -236,12 +236,27 @@ export function createRuntime({
236
236
  return { clearedUI: true };
237
237
  }
238
238
  if (cmd === 'tools') {
239
- // The slash autocomplete dropdown enumerates registered tools via
240
- // complete() listing them as a chat turn duplicates that surface
241
- // and pollutes history. Reopen the dropdown in arg-mode instead;
242
- // same primitive /help and /model adopted via openCompletions.
239
+ // No-arg form opens the autocomplete dropdown (same surface /help and
240
+ // /model adopted via openCompletions) so users can browse without
241
+ // polluting chat history. With an arg the user picked a specific
242
+ // tool render its description + schema as a reply so the dropdown
243
+ // selection has a meaningful outcome instead of looping back.
243
244
  if (registeredTools.size === 0) return { reply: 'No tools registered.' };
244
- return { openCompletions: true };
245
+ const arg = args.trim();
246
+ if (!arg) return { openCompletions: true };
247
+ const tool = registeredTools.get(arg);
248
+ if (!tool) {
249
+ const all = Array.from(registeredTools.keys()).map((n) => `\`${n}\``).join(', ');
250
+ return { reply: `Unknown tool \`${arg}\`. Available: ${all}` };
251
+ }
252
+ const lines = [`**\`${tool.name}\`** — ${tool.description || '(no description)'}`];
253
+ const schema = tool.schema || tool.input_schema;
254
+ if (schema && Object.keys(schema.properties || {}).length > 0) {
255
+ lines.push('', '```json', JSON.stringify(schema, null, 2), '```');
256
+ } else if (schema) {
257
+ lines.push('', '(no arguments)');
258
+ }
259
+ return { reply: lines.join('\n') };
245
260
  }
246
261
  if (cmd === 'model' && models.length) {
247
262
  const arg = args.trim();