@wrenautomation/birdwatch

中文文档
0.30.6发布于 2026/11/03PolyForm-Strict-1.0.0TypeScriptES Module构建来源已验证

从开放的网络上进行研究,由代理驱动,每个命令执行一步:计划,搜索,分类,打开,在报价门后面提取,检查,审查,分类账中的每条记录。代理人决定;发动机按固定的步骤运转。请求和计划文件,文件

中文使用文档
文档目录3 节
  1. 命令行界面
  2. 图书馆
  3. 开发

birdwatch

来自开放网络的研究,由一个代理驱动,每个命令一步。代理计划,分类, 检查和停止;观鸟者搜索,打开页面,在报价门后提取发现,检查 他们,并把每一个记录在一个分类账上。每一个发现都是一个句子,在页面上引用 运行阅读。 skills/birdwatch/SKILL.md (在这个回购中)是代理如何驱动它。

阅读网页和文件(获取阶梯,HTML和PDF文本,视频)是 @wrenautomation/read每个模特的电话都接通了 @wrenautomation/models。在0.29.0之前,有三个软件包:raven(一个模型规划器,在0.30.0时消失了) 代理计划)、猎鹰(./document)和weaver(引擎、源、分类账和CLI)。

进口做
@wrenautomation/birdwatch/engineSource (一个名字, search 和/或 open(成本); registry 计划的允许清单;座席的呼叫(planRound, search, open, extract, check, add, accept, brief),每人一步;法官的通行证(judgeHits, judgeDocuments, judgeFindings, judgeStats); fold 从运行的记录中重建运行的状态,因此再次步进运行会跳过已完成的操作; Transient失败值得再试一次;ask和plan文件形状(Ask, PlanFile, Query, QueryTree, Edge, Snapshot),以及每一品种的股票计划档案(web, video, channel, person, site来源,预算, age, rules,查询树指南)
@wrenautomation/birdwatch/sourcessearxng, exa (搜索), youtube (搜索和读取,yt-dlp), fetcher (开门,礼貌的取货者) ladder (打开autobrowse的取回阶梯到浏览器), reddit 和 facebook (通过autobrowse的站点路由打开一个线程或群组帖子), google (b谷歌通过桌面浏览器自己的页面:每个结果一个点击,AI概述一个点击,其文本作为片段,每个页面引用一个点击), arxiv (搜索和读取:里面的API BIRDWATCH_ARXIV_CATEGORIES,每次点击都以OpenAlex的引用次数和评论为主导;全文从HTML中读取,否则从PDF中读取;每3秒呼叫一次; paste (一个人的网址), ledger (命中较早的运行看到)。的查询 site 跳过无法保持它的搜索器(Source.keeps: youtube 只在YouTube上播放)。A跟随(Source.follows, follow)列出页面作者的帖子(youtube:一个频道的上传,从视频或频道,以及TikTok的个人资料; reddit:用户最热门的帖子和评论)或类似的页面(exa: findSimilar)
@wrenautomation/birdwatch/ledger记录(query, hit, document, finding, verdict, call, spend, snapshot, edge, done, steer, gap, check, pattern, found, judge, person), FilesLedger (一个文件夹: runs/<run>/<writer>.jsonl, plans/<kind>.json), MemoryLedger,每个来源、每个人、每个渠道和每个种类的产量行
@wrenautomation/birdwatch/document文件方面: Document, Finding, Proof, Verdict (zod)、媒体读者(html, pdf, text), claimExtractor (引用文档的发现,通过gate,以及对文档的判断:其质量和请求的差距;对发现或它们的长度没有上限,并且模型的输出上限从最后保存的引用继续) Model 接缝,它需要和 Cut 当一个模特的帽子剪断一个答案时,他就扔了

每条记录都承载着 from (人工智能,人或工具)和 by (代理或模型id、来源 人)。一个人的保留或删除记录与代理人的记录相同。计划文件归档 plans/<kind>.json 在分类帐(来源、预算、年龄、规则、树指南)旁边是一个运行的地方 学习: birdwatch learn <kind> 从跑步中学到的东西中写出下一个版本 协议;没有调优文件的类型运行库存文件(birdwatch plans <kind> 打印)。 brief.guide 向代理人显示种类的年龄判决和规则。

命令行界面

需要节点24+。 read 和 watch 需要yt-dlp和ffmpeg。

npm i @wrenautomation/birdwatch
npx birdwatch fetch https://example.com/report --contact [email protected]   # a page as text
GEMINI_API_KEY=... npx birdwatch read https://www.youtube.com/watch?v=...    # captions + screen
COHERE_API_KEY=... npx birdwatch read https://www.instagram.com/reel/...     # watched: speech, screen, cuts
npx birdwatch list 'ytsearch10:cold email' --to 10                           # hits as JSON, no downloads
npx birdwatch text report.pdf                                             # a file on disk as text
npx birdwatch page saved.html --url https://example.com/report            # title, text, links as JSON
COHERE_API_KEY=... npx birdwatch watch talk.mp4                           # speech, on-screen text, cuts
npx birdwatch plans web > ledger/plans/web.json                           # a stock plan file, to tune

一个代理(Claude Code,或任何带有shell的代理)每次只执行一个命令来驱动引擎:it 在它自己的头脑中计划,分类,审查和停止,引擎做固定的工作(搜索, 打开,提取报价门后,检查)并保存记录。每个命令打印JSON。

export BIRDWATCH_AGENT=claude-code                     # the agent's id on every record it writes
birdwatch plan "how do staffing firms win repeat clients" --known "referrals convert"   # a run; prints its id
birdwatch plan "who buys growth help" --premise "coaches are the buyer"   # a premise gets a tree facet that tests it
birdwatch brief 01M5YS...                              # the ask, budget, sources, what is open, hits, findings, cost
birdwatch recall staffing repeat clients --not 01M5YS... # earlier runs' findings: quote, URL, source date, run; --also <ledger> per extra folder
birdwatch search 01M5YS... "staffing repeat client rate" --why "the ask's words"       # one query, then every searcher
echo '[{"terms":"...","why":"..."},{"terms":"...","why":"..."}]' | birdwatch search 01M5YS...   # a batch
birdwatch search 01M5YS... < tree.json                 # a query tree, one tier: {facets: [{name, why, tries: [[{terms, why}], [...]]}]}
birdwatch search 01M5YS... < tree.json                 # after triage, the same file: the next try of each facet still thin in kept hits
birdwatch add call 01M5YS... 01M5YT... keep --why "a survey with numbers"               # triage: a hit kept
birdwatch add call 01M5YS... 01M5YU... drop --why "a vendor page"
birdwatch open 01M5YS... 01M5YT... --url https://a.example/report --why "numbers"      # keep these, read every kept hit
birdwatch open 01M5YS... --with ladder                                                  # an opener the run lacks joins it, to open only
birdwatch show 01M5YS... 01M5YV...                     # a document's text, for the agent to read itself
birdwatch add finding 01M5YS... 01M5YV... --text "412 firms were surveyed." --quote "A 2025 survey of 412 firms"
birdwatch add check 01M5YS... 01M5YW... --ok --why "the quote says it"   # the agent's own check; --fail also drops
birdwatch extract 01M5YS...                            # or a model behind the quote gate, every document without a verdict
birdwatch check 01M5YS... -n 3                         # or a model's sample of findings read against their documents
birdwatch check 01M5YS... --patterns                   # every unchecked finding a pattern rests on
birdwatch accept 01M5YS... keep --over 0.8 --why "serves the ask"   # the judge's hints in bulk, at the agent's bar
birdwatch accept 01M5YS... class --min 0.8 --why "head of page"   # also: drop --under 0.2
birdwatch add gap 01M5YS... "no UK numbers yet"
birdwatch add steer 01M5YS... "numbers only" --human will                                # the person's word, relayed
birdwatch add pattern 01M5YS... "Repeat clients come from referrals." --on 01M5YV... 01M5YW...   # what findings say together; sites counted
birdwatch add edge 01M5YS... again --why "thin on the UK"                                # the review: a new round
birdwatch plan --run 01M5YS...                         # round 2: known, steer and what round 1 left open, in its snapshot
birdwatch plan "coaches: who pays for setters" --parent 01M5YS... --why "the best niche of round 1"   # a child run
birdwatch add dead 01M5YT... spend --why "found consumers, not buyers"   # later tries skip the facet
birdwatch follow 01M5YS... --from 01M5YV... --as posts --why "the speaker's other talks"   # the author's own posts; --as similar: pages like it; a paper: --as refs (what it cites) or citers (what cites it)
birdwatch add person 01M5YS... "Bee Speaker" --profile https://www.youtube.com/@bee --aka Bee --why "one speaker"   # one person across sites
birdwatch learn web --sources searxng exa --rounds 4   # the plan file's next version, after a good run
birdwatch learn web --thin 2                           # the tree's guide: a try under 2 new hits falls through
birdwatch learn web --show                             # the current one
birdwatch add edge 01M5YS... stop --why "enough"

plan 打开一轮:它的快照包含了问题,已知的(到目前为止的发现),每一个 舵手,上一轮还有什么空缺,允许名单和预算。没有疑问,代理人来了 通过 search 或者 add query,从不封顶。预算是一道护栏: brief 显示它,并且 一条边 again 过去的 budget.rounds 打印的是警告,而不是拒绝。 search, open, extract 和 check 每个程序运行一个步骤并打印它所写的内容(文档的文本) chars); 一个带着音符放弃出口的步骤。 open 读取每一个保存命中的运行,没有 文档; extract 每一份没有判决的文件; check 的跨文档示例 保留尚未检查的发现。 add 手动写入一条记录:查询,查找(引用) 必须逐字逐句地在文档上,否则添加失败,并带有门的“为什么”,检查(? 代理人自己对与其文件不符的调查结果的解读;失败也会丢弃它),调用(keep或 投掷命中或发现),边缘(again, stop, back --to <step>)、缺口或转向(总是如此) 人的: --human [name]). 每一个 add 需要 --why 当决策需要时。一个 --human 记录是当事人通过代理人的话: from: human, by 他们的名字。

当智能体给出一个面(研究者覆盖的边)时,一轮搜索是一个树 数字,如何,谁,相反的观点,主要来源;计划文件的 tree 指南给它们命名), 每个都按顺序尝试,每个都尝试一个查询列表。 search 每次呼叫运行一个层 Fetch:第一次调用,每个facet的第一次尝试;每次调用后,每个方面的下一次尝试 比向导留下的子弹少 thin (默认为3)。的一个侧面 thin 完成;一个方面 没有名字的呼叫等待分类;有一个面没有了,仍然很薄,这是一个缺口, 写一次。尝试失败的结果是分诊保留了什么,而不是搜索者保留了什么 返回:每个搜索者返回一个页面。 --all 负责所有方面的下一步尝试 保存。第二次查询返回的页面是 found 第一炮就录,第二炮就不录了 命中,每一击都被视为命中。 brief.hits.uncalled 列出每个 首先,用找到它的面来击打; brief.tree 用它写的东西显示每一次尝试, kept 和 uncalled 每一个方面。没有查询服务的向导facet在注释中被命名。 learn --thin <n> 或者 --tree <file> 调整指南。

代理自己读取: show <run> <document> 打印文档中存储的文本, add finding 在同一扇门后面写着它读到的东西, add check 它自己的支票。 extract 和 check 在同一扇门后面放一个模型,以增加体积;两个路径都写相同的记录。

代理人:通过代理人或亲自:

npx birdwatch add steer 01M5YS... "numbers only; skip vendor pages" --human       # what you say: the brief shows it first
npx birdwatch add gap 01M5YS... "no UK numbers yet" --human                       # what the run lacks: the next plan reads it
npx birdwatch add edge 01M5YS... back --to fetch --why "searxng was down" --human # the step to run again
npx birdwatch trace 01M5YS... --type finding spend                                # the run's records, JSON lines
npx birdwatch add call 01M5YS... 01M5YT... drop --why "a forecast, not a result" --human   # a call in your name
npx birdwatch yield --source exa                                                  # hits, reads, proposed, kept
npx birdwatch sources                                                             # what this machine can run
npx birdwatch serve --port 4747                                                   # the ledger over HTTP for a viewer, read only

模型是 anthropic 默认(Claude Haiku直接, ANTHROPIC_API_KEY; --model anthropic:sonnet|opus|id 另一个) --model gateway[:alias] Wren的LLM入门课程 (WREN_LLM_GATEWAY_URL, WREN_LLM_GATEWAY_TOKEN),或者在stdin上读取提示符的任何命令 并打印出答案(claude -p --output-format json 是克劳德代码无头)。模型确实如此 仅散装(提取,检查);代理决定。源来 来自环境: SEARXNG_URL (和 SEARXNG_TOKEN举个例子,在a后面 代理), EXA_API_KEY (或 _1..n), GEMINI_API_KEY 对于没有字幕的视频, BIRDWATCH_CONTACT 对于取回器和 arxiv (无联系人,无页面打开; OPENALEX_API_KEY免费的;给予的 arxiv 它自己的引用预算,和 SEMANTIC_SCHOLAR_API_KEY,免费,按自己的价格收费 --as refs; --sources arxiv 命名它(因为没有股票计划文件这样做),也为梯子命名 AUTOBROWSE_URL 和 AUTOBROWSE_TOKEN (一个worker的HTTP面)或 RESTATE_INGRESS_URL 和 RESTATE_AUTH_TOKEN (Restate入口,后面坐着一名办公人员; POST /desk/call; AUTOBROWSE_SERVICE 获取另一个服务名称)。同一个工人给了 reddit 和 facebook 读者。 BIRDWATCH_ACCOUNTS 指定每个站点读者可以登录的帐户 (reddit=reddit@alt); 没有条目的站点只能读为已注销。分类帐文件夹为 --ledger 或者 BIRDWATCH_LEDGER (默认 ./ledger); --writer 或者 BIRDWATCH_WRITER 在其中命名您的文件。 法官是 --judge 或者 BIRDWATCH_JUDGE (jev, jev:<model>, fake, off); 没有, jev 当 TYPESAFE_API_KEY 是,否则为空。 --no-judge 为一个命令关闭它。

每个开放源代码都声明它打开的url (opens): youtube 一个YouTube页面, fetcher 和 ladder 任何其他http(s)页面 reddit Reddit帖子或评论永久链接, facebook 一个 公共群组帖子。网站自己的阅读器(first在开幕式前轮到它了。 无论允许列表的顺序如何:它都将线程作为数据响应,其中获取的页面是一个墙。 reddit 阅读先签出(reddit-public线程的馈入);只有当那错过和 BIRDWATCH_ACCOUNTS 命名一个帐户,它是否要求再次登录。 facebook 总是 签署。用过的帽子或拒绝阅读的信都是错过;忙配置文件(503)或无应答重试。 拒绝在其原因中携带工人的访问码: need_login, platform_blocked, rate_limited 或者 upstream_broken。最后两个从未读过登录:这两个都不能解决。 读取步骤要求在调用之前,所以一个源永远不会 打开一个hit就等于不花钱。获取的页面没有任何可用的内容(403,块) 梯子的最后一个梯级还在响,一个没有读者的媒体,一个梯子的答案不是HTML这样的 作为PDF)是一个失误:源抛出,它的 spend 说 ok: false 有了理由,下一个 揭幕战轮到你了,每场揭幕战没打到的命中都是 gap 上面列出了每个原因。一个页面 它的答案是200,但仍然没有任何内容(一个captcha墙,一个“未找到”的shell,低于200) 文字)同样是错过,以标题或计数为原因。运行的 快照将其源固定在 plan: sources,允许列表,搜索,打开和跟踪; opens,注册表的其他打开器(除非 --sources 是给定的),哪个打开和跟随但是 从来没有搜索。 open --with <source> 写入一个新快照,该快照将一个添加到 opens (读 注:当命中未命中时,会命名它们)。这个 梯子花费了浏览时间和工人每天的工作时间 fetch 每个调用的桶。穰的搜索 要求每个结果有一个亮点(三个句子,每个结果计费)作为命中的 snippet.

每个模型调用都是一个 spend 记录模型id,输入和输出令牌,以及 usd 从 标价(src/app/prices.ts:克劳德的俳句、十四行诗和作品5.5;网关的 free 别名为$0;另一种模式保留代币,没有价格)。 run 在stderr上打印运行总数 和作为 cost 在JSON中,最后一次复习的边缘(edge(下一个和为什么)同样的方式; brief 将总数打印为 cost.

run 当运行在一个放弃的步骤上停止时退出2(没有模型,没有源,一个块): --resume 一旦问题解决了就继续。失败值得再试一次(A 429, A 5xx, A 断开连接)尝试三次并暂停,每次尝试a spend 记录;一个步骤 仍然不能继续写不 done, run 等待并重新开始,最多五次, 在它退出之前。搜索、读取和摘录呈扇形分布(一次读取或摘录四次); 每个文档的记录在其批处理结束时着陆,并且再次执行步骤会跳过其记录 显示完成。永远失败的提取(模型的答案无法解析,为400)将停止 根据目前记录的调查结果和出口2: extract 再次只要求 没有判决的文件。削减产出上限的一个模型答案不是失败,而是整体失败 发现之前的削减通过闸门和模型再次要求其余的 已知这些发现的文件(./document的 Cut;这个 spend 携带两个调用(令牌)。

轮盘之间,这个人看书 brief (或代理人告诉他们),保留或丢弃发现(add call),并以自由文本(add steer). 每一个 steer 记录显示首先在 简短的,在它之后的回合的摘录提示。 budget.rounds 是一名警卫 铁轨,不是停止规则:通过它,边缘的原因说明了为什么再打一回合是值得的。

这些步骤用英语记录。每个搜索者都回答了这个问题,没有新的命中,并且保留了一个 打无源打不开(一个403,一个挡梯子打不开),各写一个 gap; 那么 add gap。一轮的回顾读的是差距和一个人的去留与其原因;接下来的 Round的计划会读取它们,而评论就是为什么 again,在“最后一轮未结束”下。 add edge back --to <step> 写一个人的边缘:折叠把它当作代理人。一个 pattern (add pattern用代理人的话说,是几份保存下来的调查结果的总和;它的计数 不同的地点是从发现的证据中计算出来的,从未声称过,并且 brief.patterns 列表 他们的报告。跑步可以是一个孩子(--parent <run> --why):它的快照命名父快照,它的计划读 父母和兄弟姐妹发现了什么(回想那些运行),它的预算是父母的 最多。计划文件的 runs.depth (2)是护栏:更深的孩子警告。两个封盖停止 每轮家长的子女数(runs.children, 6),整棵树的读数为(runs.reads,固定 在根目录的快照上 treeReads; 默认情况下,根节点的读数为x,四舍五入x(子节点+ 1)。 open 在树冠处停止或切断它的攻击; brief.lineage 和 brief.treeRoom 显示了 先人又离开了房间。一个 停止儿童的停止,模式和死角(add dead)达到父母的下一个计划 已知线;一个奔跑的孩子是开放的。一个 class (add class)表示文件的来源类型(原始数据、调查、 从业者,供应商,论坛,新闻,其他),以及为什么;它的研究结果证明了这一点,而且是一门课 发现超越了它。 brief.patterns[].classes 计算每个类的来源:不同的站点, 但每个论坛线程都有自己的; echo 标记一个分类源都是供应商的模式, 和 unchecked 列出未检查到的结果。只有代理人或一个人写 类。一个树面 needs 命名可以证明这一点的类; tree.facets[].lacks 说 它的读页没有(而facet没有) enough),以及其每次尝试都标记一个站点的facet。一个 draft (add draft(JSON项在stdin上)是一个粗略的草案 发现和模式:该研究的草稿门中有一个项目没有提及任何保留或有数字 没有引用过。 brief.draft 显示最新的。这永远不是最后的决定。

检查步骤读取本轮保存结果的样本(budget.checks,默认为3,或a 保存结果的十分之一,以较多者为准;0为无;分散在文件中); check --patterns 阅读每一个未检查的找到一个模式依赖,针对文本周围的每一个引用。提取门证明引用是 在纸上;检查询问它是否支持句子。失败的发现得到A check 记录和挂断电话; add call <finding> keep 把它放回去。一次失败伴随着一次补救 适合:一个较窄的句子,同样的引用。修复通过提取门和第二个 检查,然后作为新发现登陆 fixes 给旧的命名。审查看到每一个检查和发现 携带其文档的日期,因此评审将时间视为计划文件的时间 age 行说。

法官(杰夫,来自 @wrenautomation/models/judge)用概率回答输入的问题 也没有短信,所以它不会写电话或支票。 search 对每一个新的热门作品都要求它,然后去做 为客户服务,谁写的(客户,或者卖家),什么 类。 open 向每个新页面询问它的类。 check 问每个不停找的人一句:做什么 引用它,它是否归功于另一个来源。每个答案都是一个 judge 记录每一次通话 消费。他们暗示和路线: brief.hits.uncalled 按面排序然后法官判罚,然后 显示答案; documents.unclassed[].guess 显示它的等级;的一面 needs 不是 只要它的保留命中有等级(经纪人的,否则法官的),就足够了,不需要; patterns[].cites 列出信任其他来源的发现,供应商重复警告名称 他们。 check 阅读样本,再加上每一个法官支持的结果都在0.8以下:法官的回答是“不” 取出一个。 accept 在特工自己的酒吧里把提示变成记录,每个都有 法官的号码在它的为什么。 brief.judge 计算其呼叫,成本,以及代理和客户的频率 我同意。试验(0.22.0): open 还要求每个页面的 worth (你会小心吗? 研究人员引用它的问题)。 documents.toExtract[].worth 显示了它; brief.judge.worth 给出了它的AUC,以防止“对它的发现被保留”,以及半门会跳过什么。没有什么 盖茨还在研究。

从0.25.0开始,法官通读整页:正文到参考文献(附录保留) 每个部分有64000个字符,最多4个,每个部分回答最多的是“是”。杰夫的意见是 便宜(每百万代币约0.04美元),所以一张纸的成本约为十分之一美分 标准(--criterion name="question",在 plan)是一个人自己的是或否测试 好的来源:法官在每一页每一击中都问了每一个人,并且简报显示了它的几率 在每次击球(发球和测试)中作为提示。他们卑劣的种类 hits.uncalled 和 documents.toExtract; brief.judge.criteria 给出了每个人的AUC “关于它的发现被保留了下来”,在点击和页面上。只是一种暗示,而不是一扇门。

从0.27.0开始,提取器也读取主体(引用列表中没有发现)。每一个评论 查看之前每一轮的新发现和保留的发现,并决定何时停止。一篇论文的 follow --as refs 和 --as citers 列出它引用了什么和引用了什么。一次检查(25篇论文,参考十四行诗): 在整个页面上,Jev的标准赔率将十四行诗的“是”与“否”进行排序,AUC为0.94比1.00;在 摘要:0.77 ~ 1.00。

的查询记录 follow: {url, as, document?} 和术语 <as> of <url>。这个 Fetch步骤将其发送到源 follows 需要它, follow 列出多达30个,以及 点击经过分类,读取和大写就像搜索一样。每个查询都进入allow列表 就像它写的时候一样:一个来源 follow --with 允许加入连接 opens,所以它运行 跟随,从不搜索。一个 person 在网站上命名一个作者(个人资料url,他们在下面发布的名字);文件是 当一个帖子从他们的个人资料中找到它时,当它的URL位于个人资料下时,或者 当它的频道(或它的热门频道)是它们的名字之一时。 brief.people 计算每个人的 文件、保存的调查结果和地点; brief.unfollowed 列表保存了没有后续内容的页面 没有人拥有。

serve 将分类帐放在127.0.0.1以供查看者(Wren门户的Research页面)。只读: CLI仍然是唯一的写入器。 GET /runs 每次运行给出一行(ask, parent, round, next step, 计数、花)。 GET /runs/:run 给出了一个 RunView (v: 1):简短,每个查询都有命中 它写了又找,每一击都有它的来源,查询,呼叫和判断,每一页都有它的 阶级,判决和个人,每一个发现及其检查,决定和步骤的时间表结束 每个来源都有自己的理由和花费。 GET /runs/:run/documents/:doc 给出页面存储的文本。 GET /events 发送 event: run 与 {run} 每次运行文件更改时,每25秒ping一次; 然后,观众会再次看到这段视频。歌珥的答案 --origin (默认情况下是门户)和任何 localhost,并对Chrome的私有网络预飞行表示同意。这些类型生活在 src/engine/view.ts; 主机复制它们并进行检查 v美国从不进口。

图书馆

import { PoliteFetcher, userAgent } from "@wrenautomation/read/fetch";
import { readPage } from "@wrenautomation/read/text";

const fetcher = new PoliteFetcher(userAgent("[email protected]"));
const res = await fetcher.get(url);
const page = readPage(res.text, res.url);

引擎,有你自己的模型和源:

import { claimExtractor } from "@wrenautomation/birdwatch/document";
import { extract, open, planRound, registry, search } from "@wrenautomation/birdwatch/engine";
import { FilesLedger, ulids } from "@wrenautomation/birdwatch/ledger";
import { exa, fetcherSource } from "@wrenautomation/birdwatch/sources";

const ledger = new FilesLedger("./ledger", "will");
const sources = registry(exa({ keys }), fetcherSource({ fetcher }));
const deps = { sources, ledger, model, extractor: claimExtractor, clock: () => new Date(), ids: ulids(), writer: "will" };
const agent = { from: "ai" as const, by: "my-agent" };
const { run } = await planRound(deps, { ask: { text: "how do staffing firms win repeat clients", kind: "web" }, planFile, model: model.id });
await search(deps, run, [{ terms: "staffing repeat client rate", why: "the ask's words" }], agent);
await open(deps, run, { urls: ["https://a.example/report"], why: "a survey" }, agent);
await extract(deps, run); // findings, each with its proof: a quote on a page the run read

具有自己的分类帐、源或模型挂载的主机 相同的命令: addEngineCommands(program, { ledger, sources, model, extractor }) 从 @wrenautomation/birdwatch (雷恩 research 命令是这些在Postgres上)。

开发

pnpm install
pnpm lint && pnpm typecheck && pnpm test

一、 v* 标签向NPM发布(.github/workflows/release.yml可信发布:不存储令牌)。

许可证:PolyForm Strict 1.0.0 (LICENSE.md)。

版本与发布记录

@wrenautomation/birdwatch 共发布 9 个版本,首次发布于 2026/10/30;过去 12 个月发布了 9 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.30.6latest2026/11/03今天
0.30.52026/11/03今天
0.30.42026/11/03今天
0.30.32026/11/03今天
0.30.22026/11/02今天
0.30.12026/11/02今天

关于 @wrenautomation/birdwatch 的常见问题

@wrenautomation/birdwatch 是什么?

从开放的网络上进行研究,由代理驱动,每个命令执行一步:计划,搜索,分类,打开,在报价门后面提取,检查,审查,分类账中的每条记录。代理人决定;发动机按固定的步骤运转。请求和计划文件,文件

如何安装 @wrenautomation/birdwatch?

在项目目录运行 npm install @wrenautomation/birdwatch,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 birdwatch,可以用 npx birdwatch 直接运行。

@wrenautomation/birdwatch 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@wrenautomation/birdwatch 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@wrenautomation/birdwatch 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@wrenautomation/birdwatch 可以商用吗?

@wrenautomation/birdwatch 使用 PolyForm-Strict-1.0.0 许可。声明的许可为 PolyForm-Strict-1.0.0,请阅读许可原文确认使用条件。以上为概括,不构成法律意见,请以许可原文为准。

@wrenautomation/birdwatch 还在维护吗?

最新版本 0.30.6 发布于 2026/11/03(今天);至今共发布 9 个版本,其中过去 12 个月发布了 9 个;首次发布于 2026/10/30。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。