@llamaventures/cli 1.19.0 → 1.20.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/AGENT_BRIEFING.md +4 -2
- package/CHANGELOG.md +24 -0
- package/README.md +11 -4
- package/README.zh-CN.md +8 -2
- package/bin/llama-mcp.mjs +100 -124
- package/bin/llama.mjs +84 -168
- package/contracts/core-api.json +4 -4
- package/contracts/required-operations.json +336 -85
- package/lib/build-manifest.json +4 -4
- package/lib/client.mjs +1 -1
- package/package.json +1 -1
package/AGENT_BRIEFING.md
CHANGED
|
@@ -63,10 +63,11 @@ A teammate says "I just met them and heard…" or pastes a chunk of notes. Your
|
|
|
63
63
|
|
|
64
64
|
1. **Find the deal** — `llama deal search "<name>"` (Pipeline First). New name → offer to create it.
|
|
65
65
|
2. **Split what they gave you into two kinds** — this is the whole data model:
|
|
66
|
+
- **A source packet with 2+ facts, or facts + a note → ingest once.** Build a JSON object with `source`, `facts`, and optional `note`, then run `llama deal ingest <dealId> --file <packet.json>`. This is the preferred agent path: one atomic, deduplicated, retry-safe commit. Reuse an explicit `idempotencyKey` when retrying the same material. The matching MCP tool is `deal_ingest` and uses the same packet shape.
|
|
66
67
|
- **Verifiable claims → facts.** `llama deal fact add <dealId> --category <cat> --claim "…" --source "<where it came from>" --source-url <url>`. A claim someone *relayed* ("their ARR is $3M", "raised from a16z") is a fact at **unverified** trust — it's hearsay until checked. Pass `--attested` ONLY if you actually verified it against a source yourself. In raw API terms, the fact text field is `claim` (`value` is only a compatibility alias), `source` is the human-readable provenance label, and `sourceUrl` is the canonical URL.
|
|
67
68
|
- **Their judgment / impression → a note.** `llama post <dealId> "…"`. "Founder seemed evasive", "I'd lean pass", "worth a second meeting" — opinion, not fact. Attributed, never "verified".
|
|
68
69
|
- A pasted blob → pull the verifiable claims out as facts, capture their take as a note.
|
|
69
|
-
3. **Read it back before you claim it's saved.** A tool call returning `{ok:true}` is NOT proof the content is where the user will look for it.
|
|
70
|
+
3. **Read it back before you claim it's saved.** A generic tool call returning `{ok:true}` is NOT proof the content is where the user will look for it. `deal ingest` is the exception because its response is built from the rows and note block read back after commit: confirm `createdFacts`, `skippedFacts`, `note`, and `summary` in that receipt. For every other write, run `llama deal feed <dealId>` and confirm your fact/note actually appears. Never say "记好了 / saved" from a request acknowledgment alone — the #1 failure is an agent writing to the wrong surface (e.g. the brief, which is the Memo and does NOT appear in the feed) and reporting success anyway. If the authoritative ingest receipt or the feed read-back does not contain the material, fix it before reporting success.
|
|
70
71
|
- **Authorship is automatic, don't fake it.** Everything you write via CLI/MCP is recorded as "via assistant" (you're the accountable human's assistant). You can't and shouldn't make it read as human-typed — that honesty is the feature. Facts you add stay **unverified** until a human confirms them; if you pass `--attested` (only when you actually checked the source) your ceiling is **agent-verified**, never human-vouched. Only a person, signed in at the browser, can vouch. The confirmation IS the trust step — never silently mark something verified.
|
|
71
72
|
|
|
72
73
|
Why split it: facts and opinions live in different layers so the deal keeps one clean **source of truth** (facts, sourced + trust-rated) separate from people's **takes** (notes). The four layers — facts / notes / brief (AI's synthesis) / timeline — are documented in Llama Command's `docs/SCHEMA.md`.
|
|
@@ -130,6 +131,7 @@ These three look similar but land in different surfaces. Don't infer from the co
|
|
|
130
131
|
|
|
131
132
|
| You want to… | Command | Lands in |
|
|
132
133
|
|---|---|---|
|
|
134
|
+
| File a **source packet** with multiple facts and/or one note | `llama deal ingest <dealId> --file packet.json` | Facts + optional note → deal **Feed**, atomically and retry-safe |
|
|
133
135
|
| Record a **sourced, verifiable fact** | `llama deal fact add <dealId> --category <cat> --claim "…" --source "deck p3" --source-url <url>` | Facts → deal **Feed** (FACT card) + citable in the **Memo** |
|
|
134
136
|
| Leave a **comment / opinion / question / reaction** for the team | `llama post <dealId> "…"` (`@name` to notify) | Posts → deal **Feed** (POST card); `@mention` fires email + UI badge |
|
|
135
137
|
| Write **narrative that belongs in the IC memo** | `llama brief add-text <dealId> --heading "…" --body "…"` | Brief blocks → **Memo tab only — NOT in the Feed** |
|
|
@@ -298,7 +300,7 @@ Run `llama --help` for the full surface (~40 commands).
|
|
|
298
300
|
|
|
299
301
|
## MCP-native agents
|
|
300
302
|
|
|
301
|
-
If you support [MCP](https://modelcontextprotocol.io), **prefer the MCP server over parsing CLI output.** The same package ships `llama-mcp` (
|
|
303
|
+
If you support [MCP](https://modelcontextprotocol.io), **prefer the MCP server over parsing CLI output.** The same package ships `llama-mcp` (55 typed tools, identical auth chain).
|
|
302
304
|
|
|
303
305
|
Add to your MCP client config (Claude Desktop / Claude Code / Cursor / OpenClaw / Codex / etc.):
|
|
304
306
|
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,30 @@ this project adheres to [Semantic Versioning](https://semver.org).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.20.0] - 2026-07-22
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- Add `llama deal ingest <dealId> --file <packet.json>` and the matching
|
|
13
|
+
`deal_ingest` MCP tool for atomic, retry-safe source packets containing up to
|
|
14
|
+
50 facts and an optional Feed note.
|
|
15
|
+
- Add `llama pref list|add|retire|approve` and the `pref_list` / `pref_add` /
|
|
16
|
+
`pref_set_status` MCP tools for standing agent preferences (Core API 3.1.0).
|
|
17
|
+
Own user scope activates immediately; team scope requires system-admin
|
|
18
|
+
approval. Content is hard-capped at 280 chars.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- Prefer packet ingest for multi-fact agent writes; Core now canonicalizes fact
|
|
22
|
+
categories and skips exact source-aware duplicates before committing.
|
|
23
|
+
- Pin the Core API consumer contract to 3.1.0.
|
|
24
|
+
|
|
25
|
+
### Removed
|
|
26
|
+
- Remove the retired generated-persona refresh and skill-correction commands
|
|
27
|
+
from the CLI, MCP tool registry, and required Core operation inventory.
|
|
28
|
+
Llama Command keeps authenticated historical reads and 410 compatibility
|
|
29
|
+
tombstones, but new clients can no longer invoke the retired workflow.
|
|
30
|
+
- Remove `llama eval` and the `record_eval_feedback` MCP tool; the server-side
|
|
31
|
+
Golden Query Eval candidate pipeline was retired with Core API 3.0.0.
|
|
32
|
+
|
|
9
33
|
## [1.19.0] - 2026-07-16
|
|
10
34
|
|
|
11
35
|
### Added
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<strong>The Llama Ventures CLI & MCP server.</strong><br/>
|
|
9
9
|
One package, two binaries: <code>llama</code> — the CLI for humans and scripts —
|
|
10
|
-
and <code>llama-mcp</code> — a stdio MCP server with
|
|
10
|
+
and <code>llama-mcp</code> — a stdio MCP server with 55 typed tools for any
|
|
11
11
|
MCP-native agent. Both share the same auth chain, HTTP client, and error
|
|
12
12
|
format, and talk to <a href="https://command.llamaventures.vc">command.llamaventures.vc</a>.
|
|
13
13
|
</p>
|
|
@@ -98,6 +98,7 @@ llama deal feed <dealId> # every contribution, newest first
|
|
|
98
98
|
llama activity new-deals --since 24h # recent deal creations
|
|
99
99
|
llama activity updated-deals --since 7d # meaningful updates grouped by deal
|
|
100
100
|
llama deal create "Acme AI" --source alex --deal-owner owner@llamaventures.vc --source-direction Outbound --status Interested
|
|
101
|
+
llama deal ingest <dealId> --file packet.json # atomic multi-fact + optional Feed note; retry-safe
|
|
101
102
|
llama deal fact add <dealId> --category funding --claim "Raised a seed round" --source "deck p3" --source-url https://...
|
|
102
103
|
llama deal update <dealId> status Diligence
|
|
103
104
|
llama post <dealId> "note body"
|
|
@@ -113,6 +114,13 @@ Status vocabulary — `Interested`: tracked before any contact ·
|
|
|
113
114
|
signal exists. `sourceDirection` is separate: `Inbound` came to the firm,
|
|
114
115
|
`Outbound` we reached out first.
|
|
115
116
|
|
|
117
|
+
For a deck, meeting note, email, or research packet, prefer `deal ingest` over a
|
|
118
|
+
loop of `deal fact add` calls. The JSON object accepts `source`, up to 50
|
|
119
|
+
`facts`, an optional `note`, and an optional `idempotencyKey`. The server commits
|
|
120
|
+
the packet atomically, maps common category aliases into the canonical taxonomy,
|
|
121
|
+
and skips exact source-aware duplicates. `deal fact add` remains the simple path
|
|
122
|
+
for one fact.
|
|
123
|
+
|
|
116
124
|
Facts use `claim` for the fact text. `source` is a readable provenance label
|
|
117
125
|
and `sourceUrl` is the canonical evidence URL; both round-trip from the API.
|
|
118
126
|
For deal owners, use an exact `/api/field-options` `dealOwner` value, a user
|
|
@@ -129,12 +137,11 @@ reference (100+ commands). Deletes are soft and audit-logged everywhere.
|
|
|
129
137
|
| `Error[UNAUTHORIZED]` | Server rejected the credentials | Token revoked / expired / wrong account |
|
|
130
138
|
|
|
131
139
|
The MCP server returns the same prefixes inside `isError: true` content.
|
|
132
|
-
Authenticated calls send bounded, content-redacted telemetry to Command
|
|
133
|
-
`llama eval good|bad --last` turns real searches into eval feedback.
|
|
140
|
+
Authenticated calls send bounded, content-redacted telemetry to Command.
|
|
134
141
|
|
|
135
142
|
## MCP server
|
|
136
143
|
|
|
137
|
-
`llama-mcp` is a stdio Model Context Protocol server exposing
|
|
144
|
+
`llama-mcp` is a stdio Model Context Protocol server exposing 55 typed tools
|
|
138
145
|
that mirror the most-used CLI surface. Every tool is named and scoped — there
|
|
139
146
|
is deliberately no generic API passthrough. Auth is identical to the CLI's
|
|
140
147
|
chain. For the exact live list, pipe `tools/list` through it:
|
package/README.zh-CN.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<strong>Llama Ventures 的 CLI 与 MCP server。</strong><br/>
|
|
9
9
|
一个包、两个可执行文件:<code>llama</code>——给人和脚本用的 CLI;
|
|
10
|
-
<code>llama-mcp</code>——带
|
|
10
|
+
<code>llama-mcp</code>——带 55 个类型化工具的 stdio MCP server,任何
|
|
11
11
|
MCP 原生 agent 都能接。两者共享同一认证链、同一 HTTP 客户端、同一错误格式,
|
|
12
12
|
连接 <a href="https://command.llamaventures.vc">command.llamaventures.vc</a>。
|
|
13
13
|
</p>
|
|
@@ -120,6 +120,7 @@ llama deal feed <dealId> # 该 deal 的全部贡献,最新在前
|
|
|
120
120
|
llama activity new-deals --since 24h # 最近新建的 deal
|
|
121
121
|
llama activity updated-deals --since 7d # 按 deal 聚合的实质更新
|
|
122
122
|
llama deal create "Acme AI" --source alex --deal-owner owner@llamaventures.vc --source-direction Outbound --status Interested
|
|
123
|
+
llama deal ingest <dealId> --file packet.json # 多条 facts + 可选 Feed note,一次提交且可安全重试
|
|
123
124
|
llama deal fact add <dealId> --category funding --claim "Raised a seed round" --source "deck p3" --source-url https://...
|
|
124
125
|
llama deal update <dealId> status Diligence
|
|
125
126
|
llama post <dealId> "备注内容"
|
|
@@ -134,6 +135,11 @@ Status 语义——`Interested`:接触前先记录关注 · `Outreached`:已
|
|
|
134
135
|
尚无回应 · `Sourced`:已有真实关系信号。`sourceDirection` 是独立维度:
|
|
135
136
|
`Inbound` 流入,`Outbound` 我们主动。
|
|
136
137
|
|
|
138
|
+
处理 deck、会议笔记、邮件或研究材料时,优先使用 `deal ingest`,不要循环调用
|
|
139
|
+
`deal fact add`。JSON 对象支持 `source`、最多 50 条 `facts`、可选 `note` 和可选
|
|
140
|
+
`idempotencyKey`。服务端会原子提交整个材料包、把常见 category 别名归一到固定分类,
|
|
141
|
+
并跳过来源一致的精确重复。只有真正的单条事实才用 `deal fact add`。
|
|
142
|
+
|
|
137
143
|
Facts 的正文用 `claim`。`source` 是人可读来源标签,`sourceUrl` 是 canonical
|
|
138
144
|
证据 URL;两者都会从 API 回显。`dealOwner` 请用 `/api/field-options`
|
|
139
145
|
里的精确 `dealOwner` 值、用户邮箱,或数字 user id。
|
|
@@ -153,7 +159,7 @@ MCP server 在 `isError: true` 内容里返回相同前缀。认证请求会向
|
|
|
153
159
|
|
|
154
160
|
## MCP server
|
|
155
161
|
|
|
156
|
-
`llama-mcp` 是 stdio MCP server,
|
|
162
|
+
`llama-mcp` 是 stdio MCP server,55 个类型化工具镜像 CLI 最常用的命令面。
|
|
157
163
|
每个工具具名、有边界——**故意不提供**通用 API passthrough。认证链与 CLI
|
|
158
164
|
完全一致。精确工具清单以 `tools/list` 为准:
|
|
159
165
|
|
package/bin/llama-mcp.mjs
CHANGED
|
@@ -15,7 +15,6 @@ import { z } from "zod";
|
|
|
15
15
|
import {
|
|
16
16
|
getAuthHeaders,
|
|
17
17
|
getBaseUrl,
|
|
18
|
-
getLastAgentEvent,
|
|
19
18
|
readBriefing,
|
|
20
19
|
request,
|
|
21
20
|
requestSse,
|
|
@@ -84,20 +83,6 @@ function splitSources(value) {
|
|
|
84
83
|
.filter(Boolean);
|
|
85
84
|
}
|
|
86
85
|
|
|
87
|
-
function expectedIds(value) {
|
|
88
|
-
const expected = { dealIds: [], wikiSlugs: [], raw: [] };
|
|
89
|
-
if (!value) return expected;
|
|
90
|
-
const items = Array.isArray(value) ? value : String(value).split(",");
|
|
91
|
-
for (const item of items.map((s) => String(s).trim()).filter(Boolean)) {
|
|
92
|
-
const [kind, ...rest] = item.split(":");
|
|
93
|
-
const id = rest.join(":").trim();
|
|
94
|
-
if (kind === "deal" && id) expected.dealIds.push(id);
|
|
95
|
-
else if ((kind === "wiki" || kind === "slug") && id) expected.wikiSlugs.push(id);
|
|
96
|
-
else expected.raw.push(item);
|
|
97
|
-
}
|
|
98
|
-
return expected;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
86
|
function buildEnrichmentAgentMessage(args = {}) {
|
|
102
87
|
if (args.message) return String(args.message);
|
|
103
88
|
const sources = splitSources(args.sources) ?? [
|
|
@@ -257,41 +242,6 @@ server.registerTool(
|
|
|
257
242
|
}
|
|
258
243
|
);
|
|
259
244
|
|
|
260
|
-
server.registerTool(
|
|
261
|
-
"record_eval_feedback",
|
|
262
|
-
{
|
|
263
|
-
description:
|
|
264
|
-
"Mark the latest llama CLI/MCP result as good/bad or add a real query " +
|
|
265
|
-
"to the Golden Query Eval candidate pool. Use when the user says a " +
|
|
266
|
-
"Llama Command search/result was right, wrong, missing a source, or should be regression-tested.",
|
|
267
|
-
inputSchema: {
|
|
268
|
-
action: z.enum(["good", "bad", "add"]).describe("feedback action"),
|
|
269
|
-
eventId: z.number().optional().describe("agent_client_events id; defaults to latest local event"),
|
|
270
|
-
query: z.string().optional().describe("required for manual add when no source event is available"),
|
|
271
|
-
surface: z.string().optional().describe("deal, wiki, activity, people, or manual"),
|
|
272
|
-
expect: z
|
|
273
|
-
.union([z.string(), z.array(z.string())])
|
|
274
|
-
.optional()
|
|
275
|
-
.describe("expected ids like wiki:llamaos-weekly-2026-06-17 or deal:<uuid>"),
|
|
276
|
-
reason: z.string().optional().describe("why this was good/bad or should be tracked"),
|
|
277
|
-
privacyLevel: z.string().optional().describe("default internal"),
|
|
278
|
-
},
|
|
279
|
-
},
|
|
280
|
-
async ({ action, eventId, query, surface, expect, reason, privacyLevel }) => {
|
|
281
|
-
const last = getLastAgentEvent();
|
|
282
|
-
const body = {
|
|
283
|
-
action,
|
|
284
|
-
eventId: eventId ?? last?.lastEventId,
|
|
285
|
-
query,
|
|
286
|
-
surface: surface ?? last?.lastSurface,
|
|
287
|
-
expected: expectedIds(expect),
|
|
288
|
-
reason,
|
|
289
|
-
privacyLevel: privacyLevel ?? "internal",
|
|
290
|
-
};
|
|
291
|
-
return callApi("POST", "/api/agent/eval-feedback", body);
|
|
292
|
-
}
|
|
293
|
-
);
|
|
294
|
-
|
|
295
245
|
server.registerTool(
|
|
296
246
|
"skills_search",
|
|
297
247
|
{
|
|
@@ -311,6 +261,60 @@ server.registerTool(
|
|
|
311
261
|
}
|
|
312
262
|
);
|
|
313
263
|
|
|
264
|
+
server.registerTool(
|
|
265
|
+
"pref_list",
|
|
266
|
+
{
|
|
267
|
+
description:
|
|
268
|
+
"List standing agent preferences (team scope + the caller's user scope). " +
|
|
269
|
+
"These are injected into every server-side agent turn. Use status=proposed " +
|
|
270
|
+
"to review pending proposals awaiting approval.",
|
|
271
|
+
inputSchema: {
|
|
272
|
+
status: z.enum(["active", "proposed", "retired", "all"]).optional()
|
|
273
|
+
.describe("filter; defaults to active"),
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
async ({ status }) => {
|
|
277
|
+
const params = new URLSearchParams();
|
|
278
|
+
if (status) params.set("status", status);
|
|
279
|
+
return callApi("GET", `/api/agent/preferences${params.toString() ? `?${params}` : ""}`);
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
server.registerTool(
|
|
284
|
+
"pref_add",
|
|
285
|
+
{
|
|
286
|
+
description:
|
|
287
|
+
"Save a standing preference so every Llama agent follows it from the next " +
|
|
288
|
+
"turn on. Use when the user states a durable way they want agents to work " +
|
|
289
|
+
"(style, workflow, defaults). Content is hard-capped at 280 chars — if it " +
|
|
290
|
+
"does not fit, it is a procedure and belongs in a skill. Team scope needs " +
|
|
291
|
+
"system-admin approval; own user scope activates immediately.",
|
|
292
|
+
inputSchema: {
|
|
293
|
+
key: z.string().describe("short slug, e.g. reply-style.conclusion-first"),
|
|
294
|
+
content: z.string().describe("the preference, max 280 chars"),
|
|
295
|
+
scope: z.enum(["user", "team"]).optional().describe("default user (the caller)"),
|
|
296
|
+
evidence: z.string().optional().describe("what prompted this (run, correction)"),
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
async ({ key, content, scope, evidence }) =>
|
|
300
|
+
callApi("POST", "/api/agent/preferences", { key, content, scope, evidence })
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
server.registerTool(
|
|
304
|
+
"pref_set_status",
|
|
305
|
+
{
|
|
306
|
+
description:
|
|
307
|
+
"Approve (activate) or retire a standing preference by id. Own user scope " +
|
|
308
|
+
"is self-service; team scope requires a system admin.",
|
|
309
|
+
inputSchema: {
|
|
310
|
+
id: z.number().describe("preference id from pref_list"),
|
|
311
|
+
status: z.enum(["active", "retired"]).describe("new status"),
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
async ({ id, status }) =>
|
|
315
|
+
callApi("PATCH", `/api/agent/preferences/${encodeURIComponent(String(id))}`, { status })
|
|
316
|
+
);
|
|
317
|
+
|
|
314
318
|
server.registerTool(
|
|
315
319
|
"skills_read",
|
|
316
320
|
{
|
|
@@ -509,6 +513,50 @@ server.registerTool(
|
|
|
509
513
|
// Deal facts (research substrate + trust ladder)
|
|
510
514
|
// ============================================================
|
|
511
515
|
|
|
516
|
+
server.registerTool(
|
|
517
|
+
"deal_ingest",
|
|
518
|
+
{
|
|
519
|
+
description:
|
|
520
|
+
"Preferred write tool when one source yields multiple facts, or facts plus a Feed note. " +
|
|
521
|
+
"Commits the packet atomically, canonicalizes fact categories, skips exact source-aware " +
|
|
522
|
+
"duplicates, and is safe to retry with the same idempotencyKey. Use deal_fact_add only " +
|
|
523
|
+
"for a genuinely single fact. Canonical categories: company_basics, team, product, market, " +
|
|
524
|
+
"financials, fundraise, risk, milestone, meta.",
|
|
525
|
+
inputSchema: {
|
|
526
|
+
dealId: z.string(),
|
|
527
|
+
idempotencyKey: z
|
|
528
|
+
.string()
|
|
529
|
+
.optional()
|
|
530
|
+
.describe("Stable key for retries. If omitted, the server derives one from packet content."),
|
|
531
|
+
source: z
|
|
532
|
+
.object({
|
|
533
|
+
kind: z.enum(["deck", "web", "meeting_note", "email", "human", "agent_inference"]).optional(),
|
|
534
|
+
title: z.string().optional(),
|
|
535
|
+
url: z.string().optional(),
|
|
536
|
+
contentHash: z.string().optional(),
|
|
537
|
+
})
|
|
538
|
+
.optional(),
|
|
539
|
+
facts: z
|
|
540
|
+
.array(z.object({
|
|
541
|
+
category: z.string(),
|
|
542
|
+
claim: z.string(),
|
|
543
|
+
source: z.string().optional(),
|
|
544
|
+
sourceUrl: z.string().optional(),
|
|
545
|
+
sourceKind: z.enum(["deck", "web", "meeting_note", "email", "human", "agent_inference"]).optional(),
|
|
546
|
+
confidence: z.enum(["high", "medium", "low"]).optional(),
|
|
547
|
+
attested: z.boolean().optional(),
|
|
548
|
+
}))
|
|
549
|
+
.max(50)
|
|
550
|
+
.optional(),
|
|
551
|
+
note: z.string().optional().describe("Opinion, impression, or context to add to the deal Feed."),
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
async ({ dealId, ...packet }) => {
|
|
555
|
+
// @core-api-operation POST /api/deals/{dealId}/ingest
|
|
556
|
+
return callApi("POST", `/api/deals/${encodeURIComponent(dealId)}/ingest`, packet);
|
|
557
|
+
}
|
|
558
|
+
);
|
|
559
|
+
|
|
512
560
|
server.registerTool(
|
|
513
561
|
"deal_fact_list",
|
|
514
562
|
{
|
|
@@ -613,7 +661,7 @@ server.registerTool(
|
|
|
613
661
|
"accountable person, null only for principal-less system writes) and `agent` " +
|
|
614
662
|
"(the assistant/system label when an AI did the writing, null when a human " +
|
|
615
663
|
"typed it) so you can tell human-typed from assistant-drafted. The AI's " +
|
|
616
|
-
"regenerable brief
|
|
664
|
+
"regenerable brief synthesis is NOT here (that's the Memo) — only " +
|
|
617
665
|
"facts + discussion notes. Each item: kind (fact|note), ts, who, agent, " +
|
|
618
666
|
"origin, text, and for facts: source + trust rung + category.",
|
|
619
667
|
inputSchema: {
|
|
@@ -993,63 +1041,7 @@ server.registerTool(
|
|
|
993
1041
|
);
|
|
994
1042
|
|
|
995
1043
|
// ============================================================
|
|
996
|
-
//
|
|
997
|
-
// ============================================================
|
|
998
|
-
|
|
999
|
-
server.registerTool(
|
|
1000
|
-
"skill_correction_list",
|
|
1001
|
-
{
|
|
1002
|
-
description:
|
|
1003
|
-
"List the recorded corrections (long-term rules) for a persona/skill. These shape how " +
|
|
1004
|
-
"that persona's analysis is generated.",
|
|
1005
|
-
inputSchema: {
|
|
1006
|
-
skillSlug: z.string(),
|
|
1007
|
-
includeDeleted: z.boolean().optional(),
|
|
1008
|
-
},
|
|
1009
|
-
},
|
|
1010
|
-
async ({ skillSlug, includeDeleted }) => {
|
|
1011
|
-
const params = new URLSearchParams({ skill: skillSlug });
|
|
1012
|
-
if (includeDeleted) params.set("include_deleted", "1");
|
|
1013
|
-
return callApi("GET", `/api/skill-corrections?${params}`);
|
|
1014
|
-
}
|
|
1015
|
-
);
|
|
1016
|
-
|
|
1017
|
-
server.registerTool(
|
|
1018
|
-
"skill_correction_add",
|
|
1019
|
-
{
|
|
1020
|
-
description:
|
|
1021
|
-
"Record a long-term correction rule for a persona/skill (e.g. 'always check burn multiple " +
|
|
1022
|
-
"before commenting on efficiency'). ALWAYS reconfirm the distilled rule with the user before " +
|
|
1023
|
-
"calling — this changes how the persona behaves going forward. Optionally tie it to the deal/" +
|
|
1024
|
-
"block where it came up.",
|
|
1025
|
-
inputSchema: {
|
|
1026
|
-
skillSlug: z.string(),
|
|
1027
|
-
correctionText: z.string(),
|
|
1028
|
-
dealUuid: z.string().optional(),
|
|
1029
|
-
blockId: z.string().optional(),
|
|
1030
|
-
},
|
|
1031
|
-
},
|
|
1032
|
-
async ({ skillSlug, correctionText, dealUuid, blockId }) =>
|
|
1033
|
-
callApi("POST", "/api/skill-corrections", {
|
|
1034
|
-
skill_slug: skillSlug,
|
|
1035
|
-
correction_text: correctionText,
|
|
1036
|
-
triggered_in_deal_uuid: dealUuid ?? null,
|
|
1037
|
-
triggered_in_block_id: blockId ?? null,
|
|
1038
|
-
})
|
|
1039
|
-
);
|
|
1040
|
-
|
|
1041
|
-
server.registerTool(
|
|
1042
|
-
"skill_correction_delete",
|
|
1043
|
-
{
|
|
1044
|
-
description: "Soft-delete a recorded skill correction by id.",
|
|
1045
|
-
inputSchema: { id: z.union([z.string(), z.number()]) },
|
|
1046
|
-
},
|
|
1047
|
-
async ({ id }) =>
|
|
1048
|
-
callApi("DELETE", `/api/skill-corrections/${encodeURIComponent(String(id))}`)
|
|
1049
|
-
);
|
|
1050
|
-
|
|
1051
|
-
// ============================================================
|
|
1052
|
-
// Brief / persona refresh (signal-driven re-evaluation)
|
|
1044
|
+
// Brief refresh (signal-driven re-evaluation)
|
|
1053
1045
|
// ============================================================
|
|
1054
1046
|
|
|
1055
1047
|
server.registerTool(
|
|
@@ -1070,22 +1062,6 @@ server.registerTool(
|
|
|
1070
1062
|
)
|
|
1071
1063
|
);
|
|
1072
1064
|
|
|
1073
|
-
server.registerTool(
|
|
1074
|
-
"deal_refresh_persona",
|
|
1075
|
-
{
|
|
1076
|
-
description:
|
|
1077
|
-
"Regenerate one persona's analysis section for a deal. persona = a server-configured " +
|
|
1078
|
-
"persona key (unknown keys are rejected; discover the roster via agent_bootstrap). " +
|
|
1079
|
-
"Returns a runId (or null if debounced).",
|
|
1080
|
-
inputSchema: {
|
|
1081
|
-
dealId: z.string(),
|
|
1082
|
-
persona: z.string(),
|
|
1083
|
-
},
|
|
1084
|
-
},
|
|
1085
|
-
async ({ dealId, persona }) =>
|
|
1086
|
-
callApi("POST", `/api/deals/${encodeURIComponent(dealId)}/refresh-persona`, { persona })
|
|
1087
|
-
);
|
|
1088
|
-
|
|
1089
1065
|
server.registerTool(
|
|
1090
1066
|
"deal_agent_run",
|
|
1091
1067
|
{
|
package/bin/llama.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { createRequire } from "module";
|
|
4
4
|
import { randomUUID } from "crypto";
|
|
5
|
+
import { readFile } from "fs/promises";
|
|
5
6
|
import readline from "readline";
|
|
6
7
|
import {
|
|
7
8
|
DEFAULT_BASE_URL,
|
|
@@ -11,7 +12,6 @@ import {
|
|
|
11
12
|
TOKEN_FILE,
|
|
12
13
|
getAuthHeaders,
|
|
13
14
|
getBaseUrl,
|
|
14
|
-
getLastAgentEvent,
|
|
15
15
|
getToken,
|
|
16
16
|
print,
|
|
17
17
|
readBriefing,
|
|
@@ -175,45 +175,6 @@ function slugifyTitle(title) {
|
|
|
175
175
|
return slug;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
function parseExpectedIds(raw) {
|
|
179
|
-
const text = typeof raw === "string" ? raw : "";
|
|
180
|
-
const expected = { dealIds: [], wikiSlugs: [], raw: [] };
|
|
181
|
-
for (const item of text.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
182
|
-
const [kind, ...rest] = item.split(":");
|
|
183
|
-
const value = rest.join(":").trim();
|
|
184
|
-
if (kind === "deal" && value) expected.dealIds.push(value);
|
|
185
|
-
else if ((kind === "wiki" || kind === "slug") && value) expected.wikiSlugs.push(value);
|
|
186
|
-
else expected.raw.push(item);
|
|
187
|
-
}
|
|
188
|
-
return expected;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async function submitEvalFeedback(action, flags, queryText = "") {
|
|
192
|
-
const useLast = flags.last !== false;
|
|
193
|
-
const last = useLast ? getLastAgentEvent() : null;
|
|
194
|
-
const eventId =
|
|
195
|
-
flags.event && flags.event !== true
|
|
196
|
-
? Number(flags.event)
|
|
197
|
-
: last?.lastEventId ?? null;
|
|
198
|
-
if ((action === "good" || action === "bad") && !eventId && !queryText) {
|
|
199
|
-
throw new Error(`Usage: llama eval ${action} [--last] [--reason "..."]`);
|
|
200
|
-
}
|
|
201
|
-
const body = {
|
|
202
|
-
action,
|
|
203
|
-
eventId: Number.isFinite(eventId) ? eventId : undefined,
|
|
204
|
-
query: queryText || undefined,
|
|
205
|
-
surface: flags.surface && flags.surface !== true ? String(flags.surface) : last?.lastSurface ?? undefined,
|
|
206
|
-
expected:
|
|
207
|
-
flags.expect && flags.expect !== true
|
|
208
|
-
? parseExpectedIds(String(flags.expect))
|
|
209
|
-
: {},
|
|
210
|
-
reason: flags.reason && flags.reason !== true ? String(flags.reason) : undefined,
|
|
211
|
-
privacyLevel:
|
|
212
|
-
flags.privacy && flags.privacy !== true ? String(flags.privacy) : "internal",
|
|
213
|
-
};
|
|
214
|
-
return request("POST", "/api/agent/eval-feedback", body);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
178
|
// Client-side fuzzy match — used as a fallback when the server hasn't yet
|
|
218
179
|
// shipped the search/filter API (Fix B, 2026-04-25). Once the server
|
|
219
180
|
// returns the `{deals,total,limit,offset}` envelope, this path is never
|
|
@@ -403,8 +364,8 @@ Agent onboarding (run once on first install):
|
|
|
403
364
|
llama activity new-deals --since 24h # recent deal creations for agents
|
|
404
365
|
llama activity updated-deals --since 7d # meaningful deal updates, grouped
|
|
405
366
|
llama explain <url-or-object> # explain Command URL/object status + lifecycle
|
|
406
|
-
llama
|
|
407
|
-
llama
|
|
367
|
+
llama pref list [--status proposed] # standing agent preferences (injected every turn)
|
|
368
|
+
llama pref add reply-style "Lead with the conclusion." [--team]
|
|
408
369
|
|
|
409
370
|
External pitch — talk to Llama Ventures' intake agent (no token required):
|
|
410
371
|
llama pitch start --name "Jane Doe" --email "jane@acme.ai"
|
|
@@ -514,7 +475,7 @@ Brief blocks:
|
|
|
514
475
|
|
|
515
476
|
Common flags on every add-*:
|
|
516
477
|
--source-section <key> Target a structured section (team, highlights, recommendation,
|
|
517
|
-
|
|
478
|
+
landscape_map, competitors). Without this, blocks land in "_other"
|
|
518
479
|
at the bottom of the TOC. AI writers want this.
|
|
519
480
|
--reply-to <blockId> Make the block a reply to <blockId>. Snapshots parent's heading
|
|
520
481
|
+ 200-char excerpt into meta so the back-link survives parent
|
|
@@ -523,10 +484,9 @@ Brief blocks:
|
|
|
523
484
|
2026-05-03). Use bottom for batched writes that need to
|
|
524
485
|
preserve insertion order.
|
|
525
486
|
|
|
526
|
-
Brief
|
|
487
|
+
Brief refresh + agent-run revert:
|
|
527
488
|
llama deal refresh-brief <dealId> [--force] # re-eval stale sections
|
|
528
489
|
# --force = every unlocked watcher-managed section
|
|
529
|
-
llama deal refresh-persona <dealId> <persona-key> # server validates persona key
|
|
530
490
|
llama deal revert-run <dealId> <runId> --section <key> # legacy 4-section model only
|
|
531
491
|
# section: company|team|highlights|recommendation
|
|
532
492
|
|
|
@@ -536,17 +496,13 @@ Deal soft-delete / restore / trash list:
|
|
|
536
496
|
llama deal trash # list deleted deals
|
|
537
497
|
|
|
538
498
|
Deal facts (AI-extracted or human-asserted, with verification):
|
|
499
|
+
llama deal ingest <dealId> --file <packet.json> [--idempotency-key <key>] # atomic facts + optional Feed note
|
|
500
|
+
packet: {"source":{"kind":"meeting_note","title":"Office visit"},"facts":[{"category":"team","claim":"..."}],"note":"..."}
|
|
501
|
+
categories: company_basics | team | product | market | financials | fundraise | risk | milestone | meta
|
|
539
502
|
llama deal fact list <dealId>
|
|
540
503
|
llama deal fact add <dealId> --category <cat> --claim "<text>" [--source "..."] [--source-url <url>] [--confidence high|medium|low] [--attested]
|
|
541
504
|
llama deal fact verify <dealId> <factId> --status confirmed|disputed [--corrected-value "..."]
|
|
542
505
|
|
|
543
|
-
Skill corrections (persona-owner pushback — read by persona-watcher):
|
|
544
|
-
llama skill-correction list <skill-slug> [--include-deleted]
|
|
545
|
-
llama skill-correction add <skill-slug> "<correction text>" [--deal <uuid>] [--block <blockId>]
|
|
546
|
-
llama skill-correction delete <id>
|
|
547
|
-
Server enforces persona owner OR system admin on POST/DELETE; GET is open.
|
|
548
|
-
External personas (owner_email=null) are admin-only for write.
|
|
549
|
-
|
|
550
506
|
Mentions / Inbox:
|
|
551
507
|
llama mentions # default: my unresolved cues
|
|
552
508
|
llama mentions list [--everyone] [--all] # --everyone = team-wide; --all = include resolved
|
|
@@ -663,7 +619,6 @@ Common:
|
|
|
663
619
|
llama agent bootstrap live Llama OS skill manifest from Command
|
|
664
620
|
llama skills search "<query>" discover which skill to read
|
|
665
621
|
llama explain <url-or-object> explain Command URLs, 404s, deleted objects
|
|
666
|
-
llama eval bad --last mark latest CLI/MCP result as an eval candidate
|
|
667
622
|
|
|
668
623
|
Command groups — run \`llama help <group>\` for that group's commands:
|
|
669
624
|
deal create · show · feed · update · enrich · search · collaborators · links · delete
|
|
@@ -672,7 +627,7 @@ Command groups — run \`llama help <group>\` for that group's commands:
|
|
|
672
627
|
facts deal facts + skill corrections (the sourced, trust-rated layer)
|
|
673
628
|
timeline timeline · posts · mentions
|
|
674
629
|
wiki cross-deal knowledge entries (markdown or HTML)
|
|
675
|
-
|
|
630
|
+
pref standing agent preferences: list · add · retire · approve
|
|
676
631
|
memo long-form HTML investment memo
|
|
677
632
|
html deal-specific HTML artifacts (/deals/<id>/browse/<slug>)
|
|
678
633
|
pitch external founder intake (no token needed)
|
|
@@ -691,7 +646,7 @@ the CLI auto-detects it — no token needed (\`llc_\` tokens are a fallback).`;
|
|
|
691
646
|
const HELP_AREA_MATCH = {
|
|
692
647
|
deal: [/^Deals/, /^Collaborators/, /^Soft-delete/, /^Deal links/, /^Deal soft-delete/],
|
|
693
648
|
activity: [/^Agent activity/],
|
|
694
|
-
brief: [/^Brief blocks
|
|
649
|
+
brief: [/^Brief blocks/],
|
|
695
650
|
facts: [/^Deal facts/, /^Skill corrections/],
|
|
696
651
|
timeline: [/^Timeline/, /^Mentions/],
|
|
697
652
|
wiki: [/^Wiki/, /^Where does this HTML/],
|
|
@@ -1164,6 +1119,49 @@ async function main() {
|
|
|
1164
1119
|
throw new Error(`Unknown skills subcommand "${sub}". Use: list / search / show.`);
|
|
1165
1120
|
}
|
|
1166
1121
|
|
|
1122
|
+
// `llama pref ...` — standing agent preferences (learning-domain v1).
|
|
1123
|
+
// Own user scope activates immediately; team scope needs a system admin.
|
|
1124
|
+
if (area === "pref" || area === "prefs" || area === "preferences") {
|
|
1125
|
+
const sub = action;
|
|
1126
|
+
if (!sub || sub === "list") {
|
|
1127
|
+
const { flags } = parseFlags(rest, ["json", "status"]);
|
|
1128
|
+
const params = new URLSearchParams();
|
|
1129
|
+
if (flags.status && flags.status !== true) params.set("status", String(flags.status));
|
|
1130
|
+
const result = await request("GET", `/api/agent/preferences${params.toString() ? `?${params}` : ""}`);
|
|
1131
|
+
print(result);
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
if (sub === "add") {
|
|
1135
|
+
const { flags, positional } = parseFlags(rest, ["team", "evidence", "json"]);
|
|
1136
|
+
const key = positional[0];
|
|
1137
|
+
const content = positional.slice(1).join(" ").trim();
|
|
1138
|
+
if (!key || !content) {
|
|
1139
|
+
throw new Error('Usage: llama pref add <key> "<content, max 280 chars>" [--team] [--evidence "..."]');
|
|
1140
|
+
}
|
|
1141
|
+
const result = await request("POST", "/api/agent/preferences", {
|
|
1142
|
+
scope: flags.team ? "team" : "user",
|
|
1143
|
+
key,
|
|
1144
|
+
content,
|
|
1145
|
+
evidence: flags.evidence && flags.evidence !== true ? String(flags.evidence) : undefined,
|
|
1146
|
+
});
|
|
1147
|
+
print(result);
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
if (sub === "retire" || sub === "approve") {
|
|
1151
|
+
const { positional } = parseFlags(rest, ["json"]);
|
|
1152
|
+
const id = Number(positional[0]);
|
|
1153
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
1154
|
+
throw new Error(`Usage: llama pref ${sub} <id>`);
|
|
1155
|
+
}
|
|
1156
|
+
const result = await request("PATCH", `/api/agent/preferences/${id}`, {
|
|
1157
|
+
status: sub === "approve" ? "active" : "retired",
|
|
1158
|
+
});
|
|
1159
|
+
print(result);
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
throw new Error(`Unknown pref subcommand "${sub}". Use: list / add / retire / approve.`);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1167
1165
|
if (area === "explain" || (area === "agent" && action === "explain")) {
|
|
1168
1166
|
const args = area === "explain" ? [action, ...rest].filter(Boolean) : rest;
|
|
1169
1167
|
const { flags, positional } = parseFlags(args, ["json", "type", "id", "lang"]);
|
|
@@ -1201,43 +1199,6 @@ async function main() {
|
|
|
1201
1199
|
return;
|
|
1202
1200
|
}
|
|
1203
1201
|
|
|
1204
|
-
if (area === "eval") {
|
|
1205
|
-
const sub = action;
|
|
1206
|
-
if (sub === "good" || sub === "bad") {
|
|
1207
|
-
const { flags, positional } = parseFlags(rest, [
|
|
1208
|
-
"last",
|
|
1209
|
-
"event",
|
|
1210
|
-
"reason",
|
|
1211
|
-
"expect",
|
|
1212
|
-
"surface",
|
|
1213
|
-
"privacy",
|
|
1214
|
-
]);
|
|
1215
|
-
const q = positional.join(" ").trim();
|
|
1216
|
-
print(await submitEvalFeedback(sub, flags, q));
|
|
1217
|
-
return;
|
|
1218
|
-
}
|
|
1219
|
-
if (sub === "add") {
|
|
1220
|
-
const { flags, positional } = parseFlags(rest, [
|
|
1221
|
-
"event",
|
|
1222
|
-
"expect",
|
|
1223
|
-
"reason",
|
|
1224
|
-
"surface",
|
|
1225
|
-
"privacy",
|
|
1226
|
-
]);
|
|
1227
|
-
const q = positional.join(" ").trim();
|
|
1228
|
-
if (!q && !flags.event) {
|
|
1229
|
-
throw new Error(
|
|
1230
|
-
`Usage: llama eval add "<query>" --surface deal|wiki --expect wiki:<slug>|deal:<uuid>`,
|
|
1231
|
-
);
|
|
1232
|
-
}
|
|
1233
|
-
print(await submitEvalFeedback("add", flags, q));
|
|
1234
|
-
return;
|
|
1235
|
-
}
|
|
1236
|
-
throw new Error(
|
|
1237
|
-
"Usage: llama eval good|bad [--last] [--reason ...] OR llama eval add \"<query>\" --expect wiki:<slug>|deal:<uuid>",
|
|
1238
|
-
);
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
1202
|
// `llama pitch ...` — external founder-pitch family. No Llama token
|
|
1242
1203
|
// required; bootstraps a session against /api/external/* via PoW + cookie.
|
|
1243
1204
|
// See lib/external.mjs and AGENT_BRIEFING.md for the full surface.
|
|
@@ -1763,6 +1724,36 @@ async function main() {
|
|
|
1763
1724
|
return;
|
|
1764
1725
|
}
|
|
1765
1726
|
|
|
1727
|
+
// ----- Canonical source-packet ingest (atomic facts + optional Feed note) -----
|
|
1728
|
+
if (area === "deal" && action === "ingest") {
|
|
1729
|
+
const dealId = rest[0];
|
|
1730
|
+
const { flags } = parseFlags(rest.slice(1), ["file", "idempotency-key"]);
|
|
1731
|
+
if (!dealId || !flags.file || flags.file === true) {
|
|
1732
|
+
throw new Error(
|
|
1733
|
+
"Usage: llama deal ingest <dealId> --file <packet.json> [--idempotency-key <key>]\n" +
|
|
1734
|
+
'Packet: {"source":{"kind":"meeting_note","title":"Office visit"},' +
|
|
1735
|
+
'"facts":[{"category":"team","claim":"..."}],"note":"..."}'
|
|
1736
|
+
);
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
let packet;
|
|
1740
|
+
try {
|
|
1741
|
+
packet = JSON.parse(await readFile(String(flags.file), "utf8"));
|
|
1742
|
+
} catch (error) {
|
|
1743
|
+
throw new Error(`Cannot read ingest packet ${flags.file}: ${error?.message ?? String(error)}`);
|
|
1744
|
+
}
|
|
1745
|
+
if (!packet || Array.isArray(packet) || typeof packet !== "object") {
|
|
1746
|
+
throw new Error("Ingest packet must be a JSON object");
|
|
1747
|
+
}
|
|
1748
|
+
if (flags["idempotency-key"] !== undefined && flags["idempotency-key"] !== true) {
|
|
1749
|
+
packet.idempotencyKey = String(flags["idempotency-key"]);
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
// @core-api-operation POST /api/deals/{dealId}/ingest
|
|
1753
|
+
print(await request("POST", `/api/deals/${encodeURIComponent(dealId)}/ingest`, packet));
|
|
1754
|
+
return;
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1766
1757
|
// ----- Deal facts (AI-extracted or human-asserted, with verification) -----
|
|
1767
1758
|
if (area === "deal" && action === "fact") {
|
|
1768
1759
|
const sub = rest[0];
|
|
@@ -1839,24 +1830,6 @@ async function main() {
|
|
|
1839
1830
|
return;
|
|
1840
1831
|
}
|
|
1841
1832
|
|
|
1842
|
-
// ----- Persona refresh: re-run a single persona-watcher -----
|
|
1843
|
-
// Persona keys are validated server-side. Returns runId or null
|
|
1844
|
-
// (debounced / deal inactive). Used by /admin and the per-block
|
|
1845
|
-
// "重新生成" flow.
|
|
1846
|
-
if (area === "deal" && action === "refresh-persona") {
|
|
1847
|
-
const dealId = rest[0];
|
|
1848
|
-
const persona = rest[1];
|
|
1849
|
-
if (!dealId || !persona) {
|
|
1850
|
-
throw new Error(`Usage: llama deal refresh-persona <dealId> <persona-key>`);
|
|
1851
|
-
}
|
|
1852
|
-
print(await request(
|
|
1853
|
-
"POST",
|
|
1854
|
-
`/api/deals/${encodeURIComponent(dealId)}/refresh-persona`,
|
|
1855
|
-
{ persona }
|
|
1856
|
-
));
|
|
1857
|
-
return;
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1860
1833
|
// ----- Agent-run revert (legacy 4-section brief model) -----
|
|
1861
1834
|
// Reverts a single section to the `before` value snapshotted by the
|
|
1862
1835
|
// watcher run. Does NOT re-fire the watcher (intentional: human action).
|
|
@@ -2135,7 +2108,7 @@ Routing — is this the right command?
|
|
|
2135
2108
|
const meta = { updated_at: new Date().toISOString(), updated_by: "cli", by_agent: false };
|
|
2136
2109
|
|
|
2137
2110
|
// --source-section <key>: target a structured section (e.g. team /
|
|
2138
|
-
// highlights /
|
|
2111
|
+
// highlights / competitors). Without this, blocks land in the
|
|
2139
2112
|
// "_other" group at the bottom of the TOC. AI writers want this
|
|
2140
2113
|
// virtually always — without it they cannot contribute to existing
|
|
2141
2114
|
// structured sections.
|
|
@@ -2379,63 +2352,6 @@ Routing — is this the right command?
|
|
|
2379
2352
|
throw new Error(`Unknown mentions subcommand "${sub}". Use: list / show / resolve / unread.`);
|
|
2380
2353
|
}
|
|
2381
2354
|
|
|
2382
|
-
// ----- Skill corrections (persona-owner pushback workflow) -----
|
|
2383
|
-
// Persona owners (or system admins) record long-term rules each
|
|
2384
|
-
// persona-DD skill must obey. Read by the persona-watcher and prepended
|
|
2385
|
-
// to the system prompt at run time. Soft-delete is non-cascading —
|
|
2386
|
-
// deleting a row does NOT auto-fire watcher; the next natural run
|
|
2387
|
-
// (manual / stale_re_eval) just stops including the deleted rule.
|
|
2388
|
-
//
|
|
2389
|
-
// Permissions enforced server-side: only the persona owner (per
|
|
2390
|
-
// PERSONA_SKILLS in src/lib/persona-skills.ts) or a system admin can
|
|
2391
|
-
// POST or DELETE. Anyone can GET. External personas (owner_email=null)
|
|
2392
|
-
// are admin-only for write.
|
|
2393
|
-
if (area === "skill-correction") {
|
|
2394
|
-
const sub = action;
|
|
2395
|
-
|
|
2396
|
-
if (sub === "list") {
|
|
2397
|
-
const skillSlug = rest[0];
|
|
2398
|
-
if (!skillSlug) {
|
|
2399
|
-
throw new Error("Usage: llama skill-correction list <skill-slug> [--include-deleted]");
|
|
2400
|
-
}
|
|
2401
|
-
const { flags } = parseFlags(rest.slice(1));
|
|
2402
|
-
const params = new URLSearchParams({ skill: skillSlug });
|
|
2403
|
-
if (flags["include-deleted"]) params.set("include_deleted", "1");
|
|
2404
|
-
print(await request("GET", `/api/skill-corrections?${params.toString()}`));
|
|
2405
|
-
return;
|
|
2406
|
-
}
|
|
2407
|
-
|
|
2408
|
-
if (sub === "add") {
|
|
2409
|
-
const { flags, positional } = parseFlags(rest);
|
|
2410
|
-
const skillSlug = positional[0];
|
|
2411
|
-
const correctionText = positional.slice(1).join(" ").trim();
|
|
2412
|
-
if (!skillSlug || !correctionText) {
|
|
2413
|
-
throw new Error(
|
|
2414
|
-
`Usage: llama skill-correction add <skill-slug> "<correction text>" ` +
|
|
2415
|
-
`[--deal <uuid>] [--block <blockId>]`
|
|
2416
|
-
);
|
|
2417
|
-
}
|
|
2418
|
-
print(await request("POST", "/api/skill-corrections", {
|
|
2419
|
-
skill_slug: skillSlug,
|
|
2420
|
-
correction_text: correctionText,
|
|
2421
|
-
triggered_in_deal_uuid: flags.deal ? String(flags.deal) : null,
|
|
2422
|
-
triggered_in_block_id: flags.block ? String(flags.block) : null,
|
|
2423
|
-
}));
|
|
2424
|
-
return;
|
|
2425
|
-
}
|
|
2426
|
-
|
|
2427
|
-
if (sub === "delete") {
|
|
2428
|
-
const id = rest[0];
|
|
2429
|
-
if (!id) throw new Error("Usage: llama skill-correction delete <id>");
|
|
2430
|
-
print(await request("DELETE", `/api/skill-corrections/${encodeURIComponent(id)}`));
|
|
2431
|
-
return;
|
|
2432
|
-
}
|
|
2433
|
-
|
|
2434
|
-
throw new Error(
|
|
2435
|
-
`Unknown skill-correction subcommand "${sub || ""}". Use: list / add / delete.`
|
|
2436
|
-
);
|
|
2437
|
-
}
|
|
2438
|
-
|
|
2439
2355
|
// ----- Memo (long-form HTML investment memo) -----
|
|
2440
2356
|
// The Memo tab in the deal page renders HTML stored in deal_memos.
|
|
2441
2357
|
// Two sources of memo content:
|
package/contracts/core-api.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "llama.core-api-contract.v1",
|
|
3
3
|
"name": "llama-core-api",
|
|
4
|
-
"apiVersion": "1.0
|
|
4
|
+
"apiVersion": "3.1.0",
|
|
5
5
|
"openapiVersion": "3.0.3",
|
|
6
|
-
"sha256": "
|
|
7
|
-
"pathCount":
|
|
8
|
-
"operationCount":
|
|
6
|
+
"sha256": "51b134af7a63534406b3a216aeab190fd595f5270b2a10263730662f1c2f771a",
|
|
7
|
+
"pathCount": 212,
|
|
8
|
+
"operationCount": 275
|
|
9
9
|
}
|
|
@@ -2,90 +2,341 @@
|
|
|
2
2
|
"format": "llama.cli-core-api-operations.v1",
|
|
3
3
|
"coreApiContract": "contracts/core-api.json",
|
|
4
4
|
"requiredOperations": [
|
|
5
|
-
{
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
{
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
{
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
{
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
{
|
|
5
|
+
{
|
|
6
|
+
"method": "GET",
|
|
7
|
+
"path": "/api/admin/agent-events"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"method": "GET",
|
|
11
|
+
"path": "/api/admin/auth-events"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"method": "GET",
|
|
15
|
+
"path": "/api/admin/deal-events"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"method": "GET",
|
|
19
|
+
"path": "/api/agent/activity"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"method": "GET",
|
|
23
|
+
"path": "/api/agent/briefing"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"method": "POST",
|
|
27
|
+
"path": "/api/agent/client-events"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"method": "GET",
|
|
31
|
+
"path": "/api/agent/explain"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"method": "GET",
|
|
35
|
+
"path": "/api/agent/manifest"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"method": "GET",
|
|
39
|
+
"path": "/api/agent/preferences"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"method": "POST",
|
|
43
|
+
"path": "/api/agent/preferences"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"method": "PATCH",
|
|
47
|
+
"path": "/api/agent/preferences/{id}"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"method": "GET",
|
|
51
|
+
"path": "/api/agent/skills"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"method": "GET",
|
|
55
|
+
"path": "/api/agent/skills/{slug}"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"method": "GET",
|
|
59
|
+
"path": "/api/deals"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"method": "POST",
|
|
63
|
+
"path": "/api/deals/create"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"method": "GET",
|
|
67
|
+
"path": "/api/deals/deleted"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"method": "POST",
|
|
71
|
+
"path": "/api/deals/update"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"method": "DELETE",
|
|
75
|
+
"path": "/api/deals/{dealId}"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"method": "GET",
|
|
79
|
+
"path": "/api/deals/{dealId}"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"method": "POST",
|
|
83
|
+
"path": "/api/deals/{dealId}/agent-runs/{runId}/revert"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"method": "GET",
|
|
87
|
+
"path": "/api/deals/{dealId}/blocks"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"method": "PUT",
|
|
91
|
+
"path": "/api/deals/{dealId}/blocks"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"method": "DELETE",
|
|
95
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"method": "GET",
|
|
99
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"method": "PATCH",
|
|
103
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"method": "GET",
|
|
107
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}/history"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"method": "POST",
|
|
111
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}/history"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"method": "POST",
|
|
115
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}/restore"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"method": "GET",
|
|
119
|
+
"path": "/api/deals/{dealId}/collaborators"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"method": "POST",
|
|
123
|
+
"path": "/api/deals/{dealId}/collaborators"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"method": "DELETE",
|
|
127
|
+
"path": "/api/deals/{dealId}/collaborators/{userId}"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"method": "POST",
|
|
131
|
+
"path": "/api/deals/{dealId}/collaborators/{userId}/restore"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"method": "GET",
|
|
135
|
+
"path": "/api/deals/{dealId}/command-center"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"method": "GET",
|
|
139
|
+
"path": "/api/deals/{dealId}/documents"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"method": "POST",
|
|
143
|
+
"path": "/api/deals/{dealId}/documents"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"method": "DELETE",
|
|
147
|
+
"path": "/api/deals/{dealId}/documents/{slug}"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"method": "PATCH",
|
|
151
|
+
"path": "/api/deals/{dealId}/documents/{slug}"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"method": "DELETE",
|
|
155
|
+
"path": "/api/deals/{dealId}/documents/{slug}/html"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"method": "GET",
|
|
159
|
+
"path": "/api/deals/{dealId}/documents/{slug}/html"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"method": "PUT",
|
|
163
|
+
"path": "/api/deals/{dealId}/documents/{slug}/html"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"method": "GET",
|
|
167
|
+
"path": "/api/deals/{dealId}/documents/{slug}/html/history"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"method": "POST",
|
|
171
|
+
"path": "/api/deals/{dealId}/documents/{slug}/html/restore/{version}"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"method": "POST",
|
|
175
|
+
"path": "/api/deals/{dealId}/enrich"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"method": "GET",
|
|
179
|
+
"path": "/api/deals/{dealId}/facts"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"method": "POST",
|
|
183
|
+
"path": "/api/deals/{dealId}/facts"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"method": "PATCH",
|
|
187
|
+
"path": "/api/deals/{dealId}/facts/{factId}"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"method": "GET",
|
|
191
|
+
"path": "/api/deals/{dealId}/feed"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"method": "PUT",
|
|
195
|
+
"path": "/api/deals/{dealId}/founders"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"method": "POST",
|
|
199
|
+
"path": "/api/deals/{dealId}/ingest"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"method": "GET",
|
|
203
|
+
"path": "/api/deals/{dealId}/links"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"method": "POST",
|
|
207
|
+
"path": "/api/deals/{dealId}/links"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"method": "DELETE",
|
|
211
|
+
"path": "/api/deals/{dealId}/links/{linkId}"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"method": "POST",
|
|
215
|
+
"path": "/api/deals/{dealId}/links/{linkId}/restore"
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"method": "DELETE",
|
|
219
|
+
"path": "/api/deals/{dealId}/memo"
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"method": "GET",
|
|
223
|
+
"path": "/api/deals/{dealId}/memo"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"method": "POST",
|
|
227
|
+
"path": "/api/deals/{dealId}/memo"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"method": "PUT",
|
|
231
|
+
"path": "/api/deals/{dealId}/memo"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"method": "POST",
|
|
235
|
+
"path": "/api/deals/{dealId}/posts"
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"method": "POST",
|
|
239
|
+
"path": "/api/deals/{dealId}/propose-owner"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"method": "POST",
|
|
243
|
+
"path": "/api/deals/{dealId}/refresh-brief"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"method": "POST",
|
|
247
|
+
"path": "/api/deals/{dealId}/restore"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"method": "POST",
|
|
251
|
+
"path": "/api/deals/{dealId}/threads"
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"method": "POST",
|
|
255
|
+
"path": "/api/deals/{dealId}/threads/{threadId}"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"method": "GET",
|
|
259
|
+
"path": "/api/deals/{dealId}/timeline"
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"method": "POST",
|
|
263
|
+
"path": "/api/external/chat"
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"method": "POST",
|
|
267
|
+
"path": "/api/external/start-session"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"method": "POST",
|
|
271
|
+
"path": "/api/external/upload"
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"method": "GET",
|
|
275
|
+
"path": "/api/me"
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"method": "GET",
|
|
279
|
+
"path": "/api/me/nominations"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"method": "GET",
|
|
283
|
+
"path": "/api/mentions"
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"method": "GET",
|
|
287
|
+
"path": "/api/mentions/unread-count"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"method": "POST",
|
|
291
|
+
"path": "/api/mentions/{id}/resolve"
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"method": "POST",
|
|
295
|
+
"path": "/api/nominations/{approvalId}"
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"method": "GET",
|
|
299
|
+
"path": "/api/oauth/authorize"
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"method": "POST",
|
|
303
|
+
"path": "/api/oauth/revoke"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"method": "POST",
|
|
307
|
+
"path": "/api/oauth/token"
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"method": "GET",
|
|
311
|
+
"path": "/api/partner/approvals"
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"method": "POST",
|
|
315
|
+
"path": "/api/partner/approvals"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
"method": "GET",
|
|
319
|
+
"path": "/api/users"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
"method": "POST",
|
|
323
|
+
"path": "/api/wiki/save"
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"method": "GET",
|
|
327
|
+
"path": "/api/wiki/search"
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"method": "DELETE",
|
|
331
|
+
"path": "/api/wiki/{slug}"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"method": "GET",
|
|
335
|
+
"path": "/api/wiki/{slug}"
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"method": "POST",
|
|
339
|
+
"path": "/api/wiki/{slug}/restore"
|
|
340
|
+
}
|
|
90
341
|
]
|
|
91
342
|
}
|
package/lib/build-manifest.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "llama.cli-build.v1",
|
|
3
3
|
"packageName": "@llamaventures/cli",
|
|
4
|
-
"packageVersion": "1.
|
|
5
|
-
"sourceSha": "
|
|
4
|
+
"packageVersion": "1.20.0",
|
|
5
|
+
"sourceSha": "c9708c7ae6881e9e4a82972a521e748932a380ce",
|
|
6
6
|
"sourceKind": "github",
|
|
7
7
|
"sourceDirty": false,
|
|
8
8
|
"coreApiContract": {
|
|
9
9
|
"format": "llama.core-api-contract.v1",
|
|
10
10
|
"name": "llama-core-api",
|
|
11
|
-
"apiVersion": "1.0
|
|
11
|
+
"apiVersion": "3.1.0",
|
|
12
12
|
"openapiVersion": "3.0.3",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "51b134af7a63534406b3a216aeab190fd595f5270b2a10263730662f1c2f771a"
|
|
14
14
|
}
|
|
15
15
|
}
|
package/lib/client.mjs
CHANGED
|
@@ -198,7 +198,6 @@ function rememberAgentEvent(event) {
|
|
|
198
198
|
...readAgentSession(),
|
|
199
199
|
sessionId: event.sessionId || currentAgentSessionId(),
|
|
200
200
|
lastEventId: event.eventId,
|
|
201
|
-
lastCandidateId: event.candidateId ?? null,
|
|
202
201
|
lastCommand: event.command ?? null,
|
|
203
202
|
lastQuery: event.query ?? null,
|
|
204
203
|
lastSurface: event.surface ?? null,
|
|
@@ -293,6 +292,7 @@ function inferCommand(method, endpoint) {
|
|
|
293
292
|
if (pathname === "/api/deals") return verb === "GET" ? "deal.search" : "deal.write";
|
|
294
293
|
if (pathname === "/api/deals/create") return "deal.create";
|
|
295
294
|
if (pathname === "/api/deals/update") return "deal.update";
|
|
295
|
+
if (/^\/api\/deals\/[^/]+\/ingest$/.test(pathname)) return "deal.ingest";
|
|
296
296
|
if (/^\/api\/deals\/[^/]+\/threads\/[^/]+$/.test(pathname)) return "deal.agent.run";
|
|
297
297
|
if (/^\/api\/deals\/[^/]+\/threads$/.test(pathname)) return "deal.thread.create";
|
|
298
298
|
if (/^\/api\/deals\/[^/]+\/facts/.test(pathname)) return verb === "GET" ? "deal.fact.list" : "deal.fact.write";
|