echopai 2.7.0 → 2.8.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/dist/bin.js +220 -78
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -574,6 +574,28 @@ var OPERATIONS = {
|
|
|
574
574
|
]
|
|
575
575
|
}
|
|
576
576
|
},
|
|
577
|
+
"capabilities.show": {
|
|
578
|
+
cliKey: "capabilities.show",
|
|
579
|
+
cliName: "capabilities show",
|
|
580
|
+
method: "GET",
|
|
581
|
+
path: "/v1/capabilities",
|
|
582
|
+
description: "Returns the current API spec version plus a machine-readable changelog of capability changes (new endpoints, new fields, behavior fixes), newest first. Check it at session start — or after an unexpected response shape — to discover capabilities added since your integration was written. Free and unauthenticated.",
|
|
583
|
+
summary: "Capability changelog and API version discovery.",
|
|
584
|
+
positional: [],
|
|
585
|
+
outputDefault: "json",
|
|
586
|
+
pagination: "none",
|
|
587
|
+
stream: false,
|
|
588
|
+
billable: false,
|
|
589
|
+
idempotencyRequired: false,
|
|
590
|
+
scopesAny: [],
|
|
591
|
+
sideEffect: "read",
|
|
592
|
+
dryRunSupported: false,
|
|
593
|
+
inputSchema: {
|
|
594
|
+
type: "object",
|
|
595
|
+
properties: {},
|
|
596
|
+
additionalProperties: false
|
|
597
|
+
}
|
|
598
|
+
},
|
|
577
599
|
"concepts.alerts": {
|
|
578
600
|
cliKey: "concepts.alerts",
|
|
579
601
|
cliName: "concepts alerts",
|
|
@@ -1437,7 +1459,7 @@ var OPERATIONS = {
|
|
|
1437
1459
|
include_broken: {
|
|
1438
1460
|
type: "boolean",
|
|
1439
1461
|
default: false,
|
|
1440
|
-
description: "true
|
|
1462
|
+
description: "true 时连真炸板(盘中封板后跌出、当前未回封,status=broken)也一起返回;默认只返回当前封板 status=limit_up。"
|
|
1441
1463
|
}
|
|
1442
1464
|
},
|
|
1443
1465
|
additionalProperties: false
|
|
@@ -1516,7 +1538,7 @@ var OPERATIONS = {
|
|
|
1516
1538
|
cliName: "news feed",
|
|
1517
1539
|
method: "GET",
|
|
1518
1540
|
path: "/v1/news",
|
|
1519
|
-
description: "Returns recent news. Equivalent to `/v1/news/list`; retained for backward compatibility.",
|
|
1541
|
+
description: "Returns recent news. Equivalent to `/v1/news/list`; retained for backward compatibility. Partner/agent callers receive `fields=compact` by default (id, title, ai_summary, tagged securities, first ~300 chars of content); pass `fields=full` for complete content.",
|
|
1520
1542
|
summary: "List recent news.",
|
|
1521
1543
|
positional: [],
|
|
1522
1544
|
outputDefault: "json",
|
|
@@ -1529,7 +1551,16 @@ var OPERATIONS = {
|
|
|
1529
1551
|
dryRunSupported: false,
|
|
1530
1552
|
inputSchema: {
|
|
1531
1553
|
type: "object",
|
|
1532
|
-
properties: {
|
|
1554
|
+
properties: {
|
|
1555
|
+
fields: {
|
|
1556
|
+
type: "string",
|
|
1557
|
+
enum: [
|
|
1558
|
+
"compact",
|
|
1559
|
+
"full"
|
|
1560
|
+
],
|
|
1561
|
+
description: "Response shape: `compact` (the default for partner/agent callers) returns id, title, ai_summary, tagged securities, and the first ~300 chars of content with a `content_truncated` flag; `full` returns complete content."
|
|
1562
|
+
}
|
|
1563
|
+
},
|
|
1533
1564
|
additionalProperties: false
|
|
1534
1565
|
}
|
|
1535
1566
|
},
|
|
@@ -1621,6 +1652,14 @@ var OPERATIONS = {
|
|
|
1621
1652
|
minimum: 0,
|
|
1622
1653
|
default: 0,
|
|
1623
1654
|
description: "Pagination offset (page through long history ranges)."
|
|
1655
|
+
},
|
|
1656
|
+
fields: {
|
|
1657
|
+
type: "string",
|
|
1658
|
+
enum: [
|
|
1659
|
+
"compact",
|
|
1660
|
+
"full"
|
|
1661
|
+
],
|
|
1662
|
+
description: "Response shape: `compact` (the default for partner/agent callers) returns id, title/ai_summary, attribution, tagged securities, and the first ~300 chars of content with a `content_truncated` flag; `full` returns complete content. Prefer compact for scanning; fetch full text per item only when needed."
|
|
1624
1663
|
}
|
|
1625
1664
|
},
|
|
1626
1665
|
additionalProperties: false,
|
|
@@ -1686,6 +1725,14 @@ var OPERATIONS = {
|
|
|
1686
1725
|
minimum: 0,
|
|
1687
1726
|
default: 0,
|
|
1688
1727
|
description: "Pagination offset (page through long history ranges)."
|
|
1728
|
+
},
|
|
1729
|
+
fields: {
|
|
1730
|
+
type: "string",
|
|
1731
|
+
enum: [
|
|
1732
|
+
"compact",
|
|
1733
|
+
"full"
|
|
1734
|
+
],
|
|
1735
|
+
description: "Response shape: `compact` (the default for partner/agent callers) returns id, title/ai_summary, attribution, tagged securities, and the first ~300 chars of content with a `content_truncated` flag; `full` returns complete content. Prefer compact for scanning; fetch full text per item only when needed."
|
|
1689
1736
|
}
|
|
1690
1737
|
},
|
|
1691
1738
|
additionalProperties: false,
|
|
@@ -1800,7 +1847,7 @@ var OPERATIONS = {
|
|
|
1800
1847
|
cliName: "quote",
|
|
1801
1848
|
method: "GET",
|
|
1802
1849
|
path: "/v1/quote/realtime",
|
|
1803
|
-
description: "Returns real-time quotes for one or more A-share securities (canonical codes, e.g. `SSE:600519`): last price, volume, percent change, and bid/ask. Up to 200 codes per call. Requires a `quote:l1`, `quote:l2`, or `quote:delayed` scope.",
|
|
1850
|
+
description: "Returns real-time quotes for one or more A-share securities (canonical codes, e.g. `SSE:600519`): last price, volume, percent change, and bid/ask. Up to 200 codes per call. The response carries a `session` label (`pre_open` / `auction` / `open` / `break` / `closed`) and, outside continuous trading, an explanatory `note`: during 9:00–9:14 pre-open the previous session's snapshot is returned; during the 9:15–9:29 call auction, prices are indicative auction match prices. Rows whose feed has stopped updating (suspension / feed drop) keep their last snapshot and are flagged `stale: true` with `stale_since`. Requires a `quote:l1`, `quote:l2`, or `quote:delayed` scope.",
|
|
1804
1851
|
summary: "Get real-time quotes for one or more securities.",
|
|
1805
1852
|
positional: [],
|
|
1806
1853
|
outputDefault: "json",
|
|
@@ -1851,7 +1898,7 @@ var OPERATIONS = {
|
|
|
1851
1898
|
cliName: "quote scan",
|
|
1852
1899
|
method: "GET",
|
|
1853
1900
|
path: "/v1/quote/scan",
|
|
1854
|
-
description: "Returns a real-time quote for every A-share in a single call — use it for full-market scans or to discover a universe of interest when you do not yet know which codes to query. Filter with `exchange=SSE|SZSE|BSE` to narrow to one exchange. The payload is large (~3 MB, ~5,800 instruments), so pair it with `--fields`, `--jq`, or `--max-bytes` to trim it.
|
|
1901
|
+
description: "Returns a real-time quote for every A-share in a single call — use it for full-market scans or to discover a universe of interest when you do not yet know which codes to query. Filter with `exchange=SSE|SZSE|BSE` to narrow to one exchange. The payload is large (~3 MB, ~5,800 instruments), so pair it with `--fields`, `--jq`, or `--max-bytes` to trim it. The response carries a `session` label (`pre_open` / `auction` / `open` / `break` / `closed`) plus an explanatory `note` outside continuous trading: during 9:00–9:14 pre-open the previous session's snapshot is returned; during the 9:15–9:29 call auction, prices are indicative auction match prices. Instruments whose feed has stopped updating (suspension / feed drop) are excluded from the default scan; pass `include=all` to keep them, flagged with `stale: true` and `stale_since`. Each item also includes `main_net_in` (current-day cumulative net main-capital inflow in CNY, which may be negative) and a companion `main_net_in_stale` flag (true when served from the last-close fallback). Requires a `quote:l1`, `quote:l2`, or `quote:delayed` scope.",
|
|
1855
1902
|
summary: "Snapshot every A-share real-time quote in one call.",
|
|
1856
1903
|
positional: [],
|
|
1857
1904
|
outputDefault: "json",
|
|
@@ -1880,6 +1927,15 @@ var OPERATIONS = {
|
|
|
1880
1927
|
"bse"
|
|
1881
1928
|
],
|
|
1882
1929
|
description: "Filter by exchange: SSE / SZSE / BSE (case-insensitive). Omit for all."
|
|
1930
|
+
},
|
|
1931
|
+
include: {
|
|
1932
|
+
type: "string",
|
|
1933
|
+
enum: [
|
|
1934
|
+
"active",
|
|
1935
|
+
"all"
|
|
1936
|
+
],
|
|
1937
|
+
default: "active",
|
|
1938
|
+
description: "`active` (default) excludes ST, delisted, and stale (feed-dropped / suspended) instruments; `all` returns the full set with stale rows flagged."
|
|
1883
1939
|
}
|
|
1884
1940
|
},
|
|
1885
1941
|
additionalProperties: false
|
|
@@ -2259,7 +2315,7 @@ var OPERATIONS = {
|
|
|
2259
2315
|
cliName: "views feed",
|
|
2260
2316
|
method: "GET",
|
|
2261
2317
|
path: "/v1/views",
|
|
2262
|
-
description: "Returns a stream of analyst views, sell-side research, and long-form opinion. Filter by institution, analyst, security, or recency (`hours`). Requires the `views:read` scope.",
|
|
2318
|
+
description: "Returns a stream of analyst views, sell-side research, and long-form opinion. Filter by institution, analyst, security, or recency (`hours`). Partner/agent callers receive `fields=compact` by default (id, ai_summary, attribution, tagged securities, first ~300 chars of content); pass `fields=full` for complete content. Requires the `views:read` scope.",
|
|
2263
2319
|
summary: "List analyst views.",
|
|
2264
2320
|
positional: [],
|
|
2265
2321
|
outputDefault: "json",
|
|
@@ -2272,7 +2328,16 @@ var OPERATIONS = {
|
|
|
2272
2328
|
dryRunSupported: false,
|
|
2273
2329
|
inputSchema: {
|
|
2274
2330
|
type: "object",
|
|
2275
|
-
properties: {
|
|
2331
|
+
properties: {
|
|
2332
|
+
fields: {
|
|
2333
|
+
type: "string",
|
|
2334
|
+
enum: [
|
|
2335
|
+
"compact",
|
|
2336
|
+
"full"
|
|
2337
|
+
],
|
|
2338
|
+
description: "Response shape: `compact` (the default for partner/agent callers) returns id, ai_summary, attribution, tagged securities, and the first ~300 chars of content with a `content_truncated` flag; `full` returns complete content."
|
|
2339
|
+
}
|
|
2340
|
+
},
|
|
2276
2341
|
additionalProperties: false
|
|
2277
2342
|
}
|
|
2278
2343
|
},
|
|
@@ -2372,6 +2437,14 @@ var OPERATIONS = {
|
|
|
2372
2437
|
minimum: 0,
|
|
2373
2438
|
default: 0,
|
|
2374
2439
|
description: "Pagination offset (page through long history ranges)."
|
|
2440
|
+
},
|
|
2441
|
+
fields: {
|
|
2442
|
+
type: "string",
|
|
2443
|
+
enum: [
|
|
2444
|
+
"compact",
|
|
2445
|
+
"full"
|
|
2446
|
+
],
|
|
2447
|
+
description: "Response shape: `compact` (the default for partner/agent callers) returns id, title/ai_summary, attribution, tagged securities, and the first ~300 chars of content with a `content_truncated` flag; `full` returns complete content. Prefer compact for scanning; fetch full text per item only when needed."
|
|
2375
2448
|
}
|
|
2376
2449
|
},
|
|
2377
2450
|
additionalProperties: false
|
|
@@ -2490,6 +2563,14 @@ function buildCommandTree(program, dispatch) {
|
|
|
2490
2563
|
attachOperation(cmd, OPERATIONS["bars.minute-batch"], dispatch);
|
|
2491
2564
|
}
|
|
2492
2565
|
}
|
|
2566
|
+
{
|
|
2567
|
+
const noun = program.command("capabilities");
|
|
2568
|
+
noun.description("capabilities commands");
|
|
2569
|
+
{
|
|
2570
|
+
const cmd = noun.command("show");
|
|
2571
|
+
attachOperation(cmd, OPERATIONS["capabilities.show"], dispatch);
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2493
2574
|
{
|
|
2494
2575
|
const noun = program.command("concepts");
|
|
2495
2576
|
noun.description("Thematic concept boards: constituents, quotes, and alerts.");
|
|
@@ -3619,7 +3700,7 @@ import os2 from "node:os";
|
|
|
3619
3700
|
import path2 from "node:path";
|
|
3620
3701
|
|
|
3621
3702
|
// src/version.ts
|
|
3622
|
-
var CLI_VERSION = "2.
|
|
3703
|
+
var CLI_VERSION = "2.8.0";
|
|
3623
3704
|
|
|
3624
3705
|
// src/runtime/update_check.ts
|
|
3625
3706
|
var UPDATE_CACHE_PATH = path2.join(os2.homedir(), ".config", "echopai", "update_cache.json");
|
|
@@ -3752,9 +3833,10 @@ async function invoke(op, args, ctx) {
|
|
|
3752
3833
|
}
|
|
3753
3834
|
throw e;
|
|
3754
3835
|
}
|
|
3836
|
+
const opOwnedFlags = new Set(Object.keys(op.inputSchema.properties).filter((k) => SYSTEM_FLAGS.has(k)));
|
|
3755
3837
|
const apiParams = {};
|
|
3756
3838
|
for (const [k, v] of Object.entries(args)) {
|
|
3757
|
-
if (SYSTEM_FLAGS.has(k))
|
|
3839
|
+
if (SYSTEM_FLAGS.has(k) && !opOwnedFlags.has(k))
|
|
3758
3840
|
continue;
|
|
3759
3841
|
if (v === undefined || v === "")
|
|
3760
3842
|
continue;
|
|
@@ -3921,9 +4003,10 @@ async function invoke(op, args, ctx) {
|
|
|
3921
4003
|
let envelope = rawEnvelope;
|
|
3922
4004
|
try {
|
|
3923
4005
|
const jq = typeof args.jq === "string" ? args.jq : undefined;
|
|
4006
|
+
const fieldsProjection = opOwnedFlags.has("fields") ? undefined : parseFieldsFlag(args.fields);
|
|
3924
4007
|
envelope = applyFilters(rawEnvelope, {
|
|
3925
4008
|
...jq ? { query: jq } : {},
|
|
3926
|
-
...
|
|
4009
|
+
...fieldsProjection ? { fields: fieldsProjection } : {},
|
|
3927
4010
|
...parseMaxBytesFlag(args.max_bytes) ? { maxBytes: parseMaxBytesFlag(args.max_bytes) } : {}
|
|
3928
4011
|
});
|
|
3929
4012
|
} catch (e) {
|
|
@@ -4533,6 +4616,19 @@ function buildBarsBatchCommand() {
|
|
|
4533
4616
|
});
|
|
4534
4617
|
return cmd;
|
|
4535
4618
|
}
|
|
4619
|
+
// src/verbs/capabilities.ts
|
|
4620
|
+
var capabilitiesSpec = {
|
|
4621
|
+
name: "capabilities",
|
|
4622
|
+
description: "API capability changelog and spec-version discovery. Returns the current spec version plus a newest-first changelog of capability changes (new endpoints, new fields, behavior fixes). Call once at session start — or when a response shape surprises you — to learn what changed since your integration was written. Free, unauthenticated, non-billable.",
|
|
4623
|
+
inputSchema: {},
|
|
4624
|
+
handler: async (_args, ctx) => {
|
|
4625
|
+
const op = OPERATIONS["capabilities.show"];
|
|
4626
|
+
if (!op)
|
|
4627
|
+
throw new Error("capabilities.show op missing from codegen");
|
|
4628
|
+
return callOp(op, {}, ctx);
|
|
4629
|
+
},
|
|
4630
|
+
backingOps: ["capabilities.show"]
|
|
4631
|
+
};
|
|
4536
4632
|
// src/verbs/chart.ts
|
|
4537
4633
|
import { Command as Command5, Option as Option4 } from "commander";
|
|
4538
4634
|
import { z as z3 } from "zod";
|
|
@@ -5478,9 +5574,29 @@ function buildHotCommand() {
|
|
|
5478
5574
|
});
|
|
5479
5575
|
return cmd;
|
|
5480
5576
|
}
|
|
5577
|
+
// src/verbs/indices.ts
|
|
5578
|
+
import { z as z8 } from "zod";
|
|
5579
|
+
var indexSnapshotSpec = {
|
|
5580
|
+
name: "index_snapshot",
|
|
5581
|
+
description: "Real-time snapshot for the 172 A-share indices with a live quote feed (e.g. 上证指数 SSE:000001, 深证成指 SZSE:399001, 创业板指 SZSE:399006, 科创50 SSE:000688, 北证50 BSE:899050): price, pct_change, amount, speed_3min per index, refreshed ~15s during market hours (last intraday snapshot outside trading hours). Pass `codes` to narrow to a subset; omit for all 172. Use this for 'how is the broad market doing right now' — `quote` covers individual stocks only. CSI-series indices (CSI:*) have no live feed and are not returned.",
|
|
5582
|
+
inputSchema: {
|
|
5583
|
+
codes: z8.array(z8.string().regex(/^(SSE|SZSE|BSE):[0-9]{6}$/)).min(1).max(172).optional().describe("Canonical index codes to narrow the snapshot (e.g. ['SSE:000001', 'BSE:899050']); omit for all 172")
|
|
5584
|
+
},
|
|
5585
|
+
handler: async (args, ctx) => {
|
|
5586
|
+
const op = OPERATIONS["index.snapshot"];
|
|
5587
|
+
if (!op)
|
|
5588
|
+
throw new Error("index.snapshot op missing from codegen");
|
|
5589
|
+
const callArgs = {};
|
|
5590
|
+
if (Array.isArray(args.codes) && args.codes.length > 0) {
|
|
5591
|
+
callArgs.codes = args.codes.join(",");
|
|
5592
|
+
}
|
|
5593
|
+
return callOp(op, callArgs, ctx);
|
|
5594
|
+
},
|
|
5595
|
+
backingOps: ["index.snapshot"]
|
|
5596
|
+
};
|
|
5481
5597
|
// src/verbs/limit_up.ts
|
|
5482
5598
|
import { Command as Command11, Option as Option9 } from "commander";
|
|
5483
|
-
import { z as
|
|
5599
|
+
import { z as z9 } from "zod";
|
|
5484
5600
|
var DATE_RE5 = /^\d{4}-\d{2}-\d{2}$/;
|
|
5485
5601
|
var INCLUDE_VALUES = ["active", "all"];
|
|
5486
5602
|
function clampInt5(raw, min, max, fallback) {
|
|
@@ -5497,9 +5613,9 @@ var limitUpPoolSpec = {
|
|
|
5497
5613
|
name: "limit_up_pool",
|
|
5498
5614
|
description: "A-share limit-up pool for a given trade date — per-stock detail: first/last seal time, final pct, seal amount/volume, broken count, consecutive_days (连板数), board_count_within (N-day 板数), one-word-board flag, current status (limit_up / broken), board classification. Sort: consecutive_days desc → board_count_within desc → seal_amount desc. Pre-open fallback applies. Use when an agent needs the concrete list of '今天涨停了哪些票'.",
|
|
5499
5615
|
inputSchema: {
|
|
5500
|
-
trade_date:
|
|
5501
|
-
include:
|
|
5502
|
-
include_broken:
|
|
5616
|
+
trade_date: z9.string().regex(DATE_RE5).optional().describe("ISO date YYYY-MM-DD; omit for latest (pre-open fallback)"),
|
|
5617
|
+
include: z9.enum(INCLUDE_VALUES).default("active").describe("active = 排除 ST/退市(默认); all = 全部"),
|
|
5618
|
+
include_broken: z9.boolean().default(false).describe("true 时连炸板(status=broken)也一起返回;默认只返回当前封板 status=limit_up")
|
|
5503
5619
|
},
|
|
5504
5620
|
handler: async (args, ctx) => {
|
|
5505
5621
|
const op = OPERATIONS["limit-up.pool"];
|
|
@@ -5519,8 +5635,8 @@ var limitUpSummarySpec = {
|
|
|
5519
5635
|
name: "limit_up_summary",
|
|
5520
5636
|
description: "Limit-up summary for a given trade date: 涨停数 (limit_up_count) / 炸板数 (broken_count) / 跌停数 (limit_down_count) / 最高连板 (max_height) / 连板梯队 ladder[{height, count}]. 炸板/跌停 与情绪页同源 (market_breadth_intraday 当日最新分钟行). Pre-open fallback applies.",
|
|
5521
5637
|
inputSchema: {
|
|
5522
|
-
trade_date:
|
|
5523
|
-
include:
|
|
5638
|
+
trade_date: z9.string().regex(DATE_RE5).optional().describe("ISO date YYYY-MM-DD; omit for latest"),
|
|
5639
|
+
include: z9.enum(INCLUDE_VALUES).default("active").describe("active = all_a_ex_st 口径(默认); all = all_a 口径")
|
|
5524
5640
|
},
|
|
5525
5641
|
handler: async (args, ctx) => {
|
|
5526
5642
|
const op = OPERATIONS["limit-up.summary"];
|
|
@@ -5537,7 +5653,7 @@ var limitUpHistorySpec = {
|
|
|
5537
5653
|
name: "limit_up_history",
|
|
5538
5654
|
description: "Daily limit-up trend over the last N trading days: { trade_date, limit_up_count, broken_count, max_height }. 涨停数/最高连板 from market_limit_up_pool; 炸板数 from market_breadth_intraday (all_a_ex_st). Sorted by trade_date asc (oldest first).",
|
|
5539
5655
|
inputSchema: {
|
|
5540
|
-
days:
|
|
5656
|
+
days: z9.number().int().min(1).max(250).default(30).describe("Lookback window in trading days (1-250, default 30)")
|
|
5541
5657
|
},
|
|
5542
5658
|
handler: async (args, ctx) => {
|
|
5543
5659
|
const op = OPERATIONS["limit-up.history"];
|
|
@@ -5551,7 +5667,7 @@ var limitUpAnalysisSpec = {
|
|
|
5551
5667
|
name: "limit_up_analysis",
|
|
5552
5668
|
description: "Per-stock limit-up LLM attribution for a given trade date: leading_concept (主导题材) + concept_tags (相关标签) + reason (涨停理由). Themes are judged by an LLM from the latest research / views / news (NOT from the concept graph, so brand-new themes are covered) and refreshed across 6 Beijing slots daily. Complements limit-up pool (which says '哪些票涨停'); this says '为什么涨停/属什么题材'. STALE-DATA WARNING: omitting trade_date returns the latest *attributed* trading day, NOT necessarily today — before today's first slot lands (~09:47 Beijing) it falls back to the PREVIOUS day's attribution. For today's data pass trade_date explicitly and verify the returned trade_date / generated_at fields. An explicit trade_date with no attribution yet returns an empty analyses list.",
|
|
5553
5669
|
inputSchema: {
|
|
5554
|
-
trade_date:
|
|
5670
|
+
trade_date: z9.string().regex(DATE_RE5).optional().describe("ISO date YYYY-MM-DD; omit for the latest *attributed* day (falls back to the previous day until today's first slot lands ~09:47 Beijing — pass today explicitly for today's data)")
|
|
5555
5671
|
},
|
|
5556
5672
|
handler: async (args, ctx) => {
|
|
5557
5673
|
const op = OPERATIONS["limit-up.analysis"];
|
|
@@ -5617,7 +5733,7 @@ function buildLimitUpCommand() {
|
|
|
5617
5733
|
}
|
|
5618
5734
|
// src/verbs/lookup.ts
|
|
5619
5735
|
import { Command as Command12, Option as Option10 } from "commander";
|
|
5620
|
-
import { z as
|
|
5736
|
+
import { z as z10 } from "zod";
|
|
5621
5737
|
function mapLookupResponse(raw) {
|
|
5622
5738
|
if (!Array.isArray(raw))
|
|
5623
5739
|
return [];
|
|
@@ -5641,8 +5757,8 @@ var lookupSpec = {
|
|
|
5641
5757
|
name: "lookup",
|
|
5642
5758
|
description: "Resolve a Chinese name / A-share code / pinyin initials to canonical codes (e.g. SSE:600519). Use this first whenever the agent has a description but needs a canonical_code for downstream calls. AH dual-listing: when a company is listed on both A-share and HK (e.g. 工商银行 SSE:601398 / HK:01398), prefer the A-share canonical for all downstream analysis unless the user explicitly asks for the HK side.",
|
|
5643
5759
|
inputSchema: {
|
|
5644
|
-
text:
|
|
5645
|
-
limit:
|
|
5760
|
+
text: z10.string().min(1).max(50).describe("Search text: Chinese name (贵州茅台), code (600519), or pinyin (gzmt)"),
|
|
5761
|
+
limit: z10.number().int().min(1).max(30).default(10).describe("Max matches (1-30)")
|
|
5646
5762
|
},
|
|
5647
5763
|
handler: async (args, ctx) => {
|
|
5648
5764
|
const op = OPERATIONS["semantic.find"];
|
|
@@ -5676,7 +5792,7 @@ function buildLookupCommand() {
|
|
|
5676
5792
|
}
|
|
5677
5793
|
// src/verbs/market.ts
|
|
5678
5794
|
import { Command as Command13, Option as Option11 } from "commander";
|
|
5679
|
-
import { z as
|
|
5795
|
+
import { z as z11 } from "zod";
|
|
5680
5796
|
var marketStatusSpec = {
|
|
5681
5797
|
name: "market_status",
|
|
5682
5798
|
description: "Current A-share market session: pre-open / open / lunch / closed; current and next trading day; holiday flag. Cheap and non-billable — call it before any quote / bars fetch when the agent needs to decide pre-market fallback vs intraday vs after-close behavior.",
|
|
@@ -5729,10 +5845,10 @@ var marketMoversSpec = {
|
|
|
5729
5845
|
name: "market_movers",
|
|
5730
5846
|
description: "A-share market movers — top N from the full real-time snapshot, sorted by chosen field. Sort keys: `pct` (涨幅榜) / `pct_asc` (跌幅榜) / `speed` (3-min 涨速 speed_3min) / `amount` (成交额) / `turnover` (换手率 turnover_rate) / `total_mv` (总市值). Backed by `quote.scan` so 9:00-9:14 集合竞价时段会返空 (with `note`). Defaults: sort=pct, top=20, include=active (排除 ST / 退市). Use this for /market-style 'who's running today' instead of pulling the full 3 MB scan and sorting client-side.",
|
|
5731
5847
|
inputSchema: {
|
|
5732
|
-
sort:
|
|
5733
|
-
top:
|
|
5734
|
-
exchange:
|
|
5735
|
-
include:
|
|
5848
|
+
sort: z11.enum(MOVERS_SORT_VALUES).default("pct").describe("Sort field: pct / pct_asc / speed / amount / turnover / total_mv"),
|
|
5849
|
+
top: z11.number().int().min(1).max(500).default(20).describe("Top N items (1-500, default 20)"),
|
|
5850
|
+
exchange: z11.enum(EXCHANGE_VALUES).optional().describe("Narrow to one exchange: SSE / SZSE / BSE"),
|
|
5851
|
+
include: z11.enum(INCLUDE_VALUES2).default("active").describe("active = 排除 ST/退市(默认); all = 全集(含 ST + 退市 + 未知 status)")
|
|
5736
5852
|
},
|
|
5737
5853
|
handler: async (args, ctx) => {
|
|
5738
5854
|
const op = OPERATIONS["quote.scan"];
|
|
@@ -5816,18 +5932,19 @@ function buildMarketCommand() {
|
|
|
5816
5932
|
}
|
|
5817
5933
|
// src/verbs/news.ts
|
|
5818
5934
|
import { Command as Command14, Option as Option12 } from "commander";
|
|
5819
|
-
import { z as
|
|
5935
|
+
import { z as z12 } from "zod";
|
|
5820
5936
|
var newsSpec = {
|
|
5821
5937
|
name: "news",
|
|
5822
|
-
description: "SUPPLEMENTARY news / market briefs (short time-horizon event stream). Use ONLY to fill gaps not covered by `views`; prefer `views` as the primary research source. Three modes: `code` (canonical, works across A-share | HK | US — e.g. SSE:600519, HK:00700 腾讯, US:BABA) → news mentioning that security; `query` (free text) → full-text search; neither → recent time-window feed. AH dual-listing: when filtering by `code` for an A+H listed company, pass the A-share canonical (e.g. SSE:601398) for consolidated coverage; HK side only if the user explicitly asks. Note: `query` is matched against news text, so passing a canonical_code as `query` will not work — use `code` for security filtering.",
|
|
5938
|
+
description: "SUPPLEMENTARY news / market briefs (short time-horizon event stream). Use ONLY to fill gaps not covered by `views`; prefer `views` as the primary research source. Returns `fields=compact` by default (title + ai_summary + first ~300 chars of content, `content_truncated` flag) — typically 20-50x smaller than full; pass fields='full' only when you need complete article text. Three modes: `code` (canonical, works across A-share | HK | US — e.g. SSE:600519, HK:00700 腾讯, US:BABA) → news mentioning that security; `query` (free text) → full-text search; neither → recent time-window feed. AH dual-listing: when filtering by `code` for an A+H listed company, pass the A-share canonical (e.g. SSE:601398) for consolidated coverage; HK side only if the user explicitly asks. Note: `query` is matched against news text, so passing a canonical_code as `query` will not work — use `code` for security filtering.",
|
|
5823
5939
|
inputSchema: {
|
|
5824
|
-
code:
|
|
5825
|
-
query:
|
|
5826
|
-
hours:
|
|
5827
|
-
from:
|
|
5828
|
-
to:
|
|
5829
|
-
offset:
|
|
5830
|
-
limit:
|
|
5940
|
+
code: z12.string().regex(/^((SSE|SZSE|BSE):[0-9]{6}|HK:[0-9]{5}|US:[A-Z][A-Z0-9.\-]{0,5})$/).optional().describe("Filter by security canonical_code (e.g. SSE:600519, HK:00700). Takes precedence over `query`."),
|
|
5941
|
+
query: z12.string().optional().describe("Free-text query (Chinese or English) matched against news content; omit for time-window feed. Do NOT pass canonical_code here — use `code` instead."),
|
|
5942
|
+
hours: z12.number().int().min(1).max(168).default(24).describe("Rolling-feed lookback in hours (default 24 — much narrower than views). For longer history use from/to with code or query."),
|
|
5943
|
+
from: z12.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe("History range start (China date YYYY-MM-DD). Range mode: needs code or query; Pro-only up to 365 days back."),
|
|
5944
|
+
to: z12.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe("History range end (inclusive, China date; defaults to today). Use with from."),
|
|
5945
|
+
offset: z12.number().int().min(0).optional().describe("Pagination offset for paging through long history ranges."),
|
|
5946
|
+
limit: z12.number().int().min(1).max(100).default(20).describe("Max items per page"),
|
|
5947
|
+
fields: z12.enum(["compact", "full"]).optional().describe("Response shape: compact (default — title + ai_summary + first ~300 chars) or full (complete content)")
|
|
5831
5948
|
},
|
|
5832
5949
|
handler: async (args, ctx) => {
|
|
5833
5950
|
const { opKey, callArgs } = buildNewsCall(args);
|
|
@@ -5840,11 +5957,14 @@ var newsSpec = {
|
|
|
5840
5957
|
};
|
|
5841
5958
|
function buildNewsCall(args) {
|
|
5842
5959
|
const hasRange = typeof args.from === "string" && args.from.length > 0;
|
|
5960
|
+
const fields = args.fields === "compact" || args.fields === "full" ? args.fields : undefined;
|
|
5843
5961
|
const withWindow = (a) => {
|
|
5844
5962
|
if (typeof args.limit === "number")
|
|
5845
5963
|
a.limit = args.limit;
|
|
5846
5964
|
if (typeof args.offset === "number")
|
|
5847
5965
|
a.offset = args.offset;
|
|
5966
|
+
if (fields)
|
|
5967
|
+
a.fields = fields;
|
|
5848
5968
|
if (hasRange) {
|
|
5849
5969
|
a.from = args.from;
|
|
5850
5970
|
if (typeof args.to === "string" && args.to.length > 0)
|
|
@@ -5861,7 +5981,7 @@ function buildNewsCall(args) {
|
|
|
5861
5981
|
if (hasRange) {
|
|
5862
5982
|
throw new Error("range history (from/to) requires --code or --query; the bare feed has no narrowing filter");
|
|
5863
5983
|
}
|
|
5864
|
-
return { opKey: "news.feed", callArgs: {} };
|
|
5984
|
+
return { opKey: "news.feed", callArgs: fields ? { fields } : {} };
|
|
5865
5985
|
}
|
|
5866
5986
|
function clamp3(raw, min, max, fallback) {
|
|
5867
5987
|
const n = Math.floor(Number(raw));
|
|
@@ -5882,6 +6002,10 @@ function buildNewsCommand() {
|
|
|
5882
6002
|
cmd.addOption(new Option12("--to <date>", "History range end YYYY-MM-DD (inclusive; default today)"));
|
|
5883
6003
|
cmd.addOption(new Option12("--offset <n>", "Pagination offset for long history").default("0"));
|
|
5884
6004
|
cmd.addOption(new Option12("--limit <n>", "Max items").default("20"));
|
|
6005
|
+
cmd.addOption(new Option12("--fields <mode>", "Response shape: compact (default) or full").choices([
|
|
6006
|
+
"compact",
|
|
6007
|
+
"full"
|
|
6008
|
+
]));
|
|
5885
6009
|
cmd.action(async (opts) => {
|
|
5886
6010
|
const args = {
|
|
5887
6011
|
hours: clamp3(opts.hours, 1, 168, 24),
|
|
@@ -5896,19 +6020,21 @@ function buildNewsCommand() {
|
|
|
5896
6020
|
args.from = opts.from;
|
|
5897
6021
|
if (opts.to)
|
|
5898
6022
|
args.to = opts.to;
|
|
6023
|
+
if (opts.fields)
|
|
6024
|
+
args.fields = opts.fields;
|
|
5899
6025
|
await executeVerb(async (ctx) => newsSpec.handler(args, ctx));
|
|
5900
6026
|
});
|
|
5901
6027
|
return cmd;
|
|
5902
6028
|
}
|
|
5903
6029
|
// src/verbs/quote.ts
|
|
5904
6030
|
import { Command as Command15, Option as Option13 } from "commander";
|
|
5905
|
-
import { z as
|
|
6031
|
+
import { z as z13 } from "zod";
|
|
5906
6032
|
var quoteSpec = {
|
|
5907
6033
|
name: "quote",
|
|
5908
6034
|
description: "Real-time quote for 1-200 A-share securities (last price, volume, change %, bid/ask). For >200 codes use `scan` instead. AH dual-listing: HK codes are not supported here; for an A+H listed company use the A-share canonical (e.g. SSE:601398 not HK:01398).",
|
|
5909
6035
|
inputSchema: {
|
|
5910
|
-
codes:
|
|
5911
|
-
include_l2:
|
|
6036
|
+
codes: z13.array(z13.string().regex(/^(SSE|SZSE|BSE|SH|SZ|BJ):[0-9]{6}$/)).min(1).max(200).describe("Array of canonical codes (e.g. ['SSE:600519', 'SZSE:000001'])"),
|
|
6037
|
+
include_l2: z13.boolean().optional().describe("Include L2 5-level order book (requires quote:l2 scope)")
|
|
5912
6038
|
},
|
|
5913
6039
|
handler: async (args, ctx) => {
|
|
5914
6040
|
const op = OPERATIONS["quote"];
|
|
@@ -5939,12 +6065,12 @@ function buildQuoteCommand() {
|
|
|
5939
6065
|
}
|
|
5940
6066
|
// src/verbs/scan.ts
|
|
5941
6067
|
import { Command as Command16, Option as Option14 } from "commander";
|
|
5942
|
-
import { z as
|
|
6068
|
+
import { z as z14 } from "zod";
|
|
5943
6069
|
var scanSpec = {
|
|
5944
6070
|
name: "scan",
|
|
5945
6071
|
description: "Full-market real-time quote scan (~5800 A-share securities in one round-trip). Use for universe discovery; agents should slim output with field/byte limits in their tool host or post-processing.",
|
|
5946
6072
|
inputSchema: {
|
|
5947
|
-
exchange:
|
|
6073
|
+
exchange: z14.enum(["SSE", "SZSE", "BSE"]).optional().describe("Filter by exchange (omit for all)")
|
|
5948
6074
|
},
|
|
5949
6075
|
handler: async (args, ctx) => {
|
|
5950
6076
|
const op = OPERATIONS["quote.scan"];
|
|
@@ -5973,16 +6099,16 @@ function buildScanCommand() {
|
|
|
5973
6099
|
}
|
|
5974
6100
|
// src/verbs/search.ts
|
|
5975
6101
|
import { Command as Command17, Option as Option15 } from "commander";
|
|
5976
|
-
import { z as
|
|
6102
|
+
import { z as z15 } from "zod";
|
|
5977
6103
|
var searchSpec = {
|
|
5978
6104
|
name: "search",
|
|
5979
6105
|
description: "Structured-first hybrid search across analyst views + news (views weighted higher per feedback_views_over_news). Three lanes — entity (company codes / names, analyst names), concept-graph hub (theme alias → concept → constituents & research), and ParadeDB BM25 full-text (jieba) — fused with RRF. Deterministic & explainable: no vector kNN, no LLM rerank. Best for theme/concept queries: 'CPO' brings out 光模块/光通信/光芯片; '减肥药' brings out 创新药; '智驾' brings out 智能驾驶. Use `news` or `views` instead if you need strict time-window listing.",
|
|
5980
6106
|
inputSchema: {
|
|
5981
|
-
q:
|
|
5982
|
-
type:
|
|
5983
|
-
mode:
|
|
5984
|
-
hours:
|
|
5985
|
-
limit:
|
|
6107
|
+
q: z15.string().min(1).max(200).describe("Free-text query (Chinese or English)"),
|
|
6108
|
+
type: z15.enum(["news", "views", "all"]).default("all").describe("Search scope (views weighted higher in 'all')"),
|
|
6109
|
+
mode: z15.enum(["hybrid", "exact"]).default("hybrid").describe("hybrid = entity + concept-graph + BM25 fused; exact = BM25 keyword only"),
|
|
6110
|
+
hours: z15.number().int().min(1).max(720).optional().describe("Lookback window in hours; omit for no time limit"),
|
|
6111
|
+
limit: z15.number().int().min(1).max(50).default(20).describe("Max items returned")
|
|
5986
6112
|
},
|
|
5987
6113
|
handler: async (args, ctx) => {
|
|
5988
6114
|
const op = OPERATIONS["search.semantic"];
|
|
@@ -6035,7 +6161,7 @@ function buildSearchCommand() {
|
|
|
6035
6161
|
}
|
|
6036
6162
|
// src/verbs/sentiment.ts
|
|
6037
6163
|
import { Command as Command18, Option as Option16 } from "commander";
|
|
6038
|
-
import { z as
|
|
6164
|
+
import { z as z16 } from "zod";
|
|
6039
6165
|
var SCOPE_VALUES = [
|
|
6040
6166
|
"all_a",
|
|
6041
6167
|
"all_a_ex_st",
|
|
@@ -6059,8 +6185,8 @@ var sentimentSpec = {
|
|
|
6059
6185
|
name: "sentiment",
|
|
6060
6186
|
description: "Aggregate market sentiment indicators (limit-up/down counts, breadth, divergence index, top movers). Defaults to all_a_ex_st (all A-shares ex-ST). Pass `at_date` (YYYY-MM-DD) for any historical trading day; omit for today's latest snapshot. Backward-compat alias of `sentiment_overview` — prefer the latter in new agent code.",
|
|
6061
6187
|
inputSchema: {
|
|
6062
|
-
scope:
|
|
6063
|
-
at_date:
|
|
6188
|
+
scope: z16.enum(SCOPE_VALUES).default("all_a_ex_st").describe("Universe filter"),
|
|
6189
|
+
at_date: z16.string().regex(DATE_RE6).optional().describe("Trade date YYYY-MM-DD; omit for today's realtime snapshot")
|
|
6064
6190
|
},
|
|
6065
6191
|
handler: async (args, ctx) => {
|
|
6066
6192
|
const op = OPERATIONS["sentiment.overview"];
|
|
@@ -6077,8 +6203,8 @@ var sentimentOverviewSpec = {
|
|
|
6077
6203
|
name: "sentiment_overview",
|
|
6078
6204
|
description: "Aggregate sentiment snapshot for one trading day's latest minute: up/down/flat counts, limit-up/down, gt3/lt3 breadth, divergence index + label, MA20/50/200 breadth, 52w new high/low. `at_date` omitted = today realtime (Redis); explicit YYYY-MM-DD = historical from ClickHouse `market_breadth_intraday` last minute.",
|
|
6079
6205
|
inputSchema: {
|
|
6080
|
-
scope:
|
|
6081
|
-
at_date:
|
|
6206
|
+
scope: z16.enum(SCOPE_VALUES).default("all_a_ex_st").describe("Universe filter"),
|
|
6207
|
+
at_date: z16.string().regex(DATE_RE6).optional().describe("Trade date YYYY-MM-DD; omit for today realtime")
|
|
6082
6208
|
},
|
|
6083
6209
|
handler: async (args, ctx) => {
|
|
6084
6210
|
const op = OPERATIONS["sentiment.overview"];
|
|
@@ -6095,8 +6221,8 @@ var sentimentBreadthSpec = {
|
|
|
6095
6221
|
name: "sentiment_breadth",
|
|
6096
6222
|
description: "Intraday breadth time series for one trading day (up to 241 minute bars; 13:00 excluded due to sparse Sina ticks). `at_date` omitted = today (pre-open returns empty); explicit YYYY-MM-DD = historical replay. Returns per-minute rows of up/down/flat/limit_up/limit_down/breadth/divergence fields — same shape as `sentiment_overview` per row.",
|
|
6097
6223
|
inputSchema: {
|
|
6098
|
-
scope:
|
|
6099
|
-
at_date:
|
|
6224
|
+
scope: z16.enum(SCOPE_VALUES).default("all_a_ex_st").describe("Universe filter"),
|
|
6225
|
+
at_date: z16.string().regex(DATE_RE6).optional().describe("Trade date YYYY-MM-DD; omit for today")
|
|
6100
6226
|
},
|
|
6101
6227
|
handler: async (args, ctx) => {
|
|
6102
6228
|
const op = OPERATIONS["sentiment.breadth"];
|
|
@@ -6113,9 +6239,9 @@ var sentimentTurnoverSpec = {
|
|
|
6113
6239
|
name: "sentiment_turnover",
|
|
6114
6240
|
description: "Intraday turnover time series with `current_turnover` / `predicted_total` / `delta_vs_yesterday` headline fields. `at_date` omitted = today (pre-open returns nulls); explicit YYYY-MM-DD = historical. `days` (1-5) pulls that day + N-1 prior trading days for same-minute YoY comparison.",
|
|
6115
6241
|
inputSchema: {
|
|
6116
|
-
scope:
|
|
6117
|
-
at_date:
|
|
6118
|
-
days:
|
|
6242
|
+
scope: z16.enum(SCOPE_VALUES).default("all_a_ex_st").describe("Universe filter"),
|
|
6243
|
+
at_date: z16.string().regex(DATE_RE6).optional().describe("Trade date YYYY-MM-DD; omit for today"),
|
|
6244
|
+
days: z16.number().int().min(1).max(5).default(1).describe("at_date 当日 + 之前 days-1 天(1-5,默认 1)")
|
|
6119
6245
|
},
|
|
6120
6246
|
handler: async (args, ctx) => {
|
|
6121
6247
|
const op = OPERATIONS["sentiment.turnover"];
|
|
@@ -6210,19 +6336,20 @@ function buildSentimentCommand() {
|
|
|
6210
6336
|
}
|
|
6211
6337
|
// src/verbs/views.ts
|
|
6212
6338
|
import { Command as Command19, Option as Option17 } from "commander";
|
|
6213
|
-
import { z as
|
|
6339
|
+
import { z as z17 } from "zod";
|
|
6214
6340
|
var viewsSpec = {
|
|
6215
6341
|
name: "views",
|
|
6216
|
-
description: "PRIMARY research source for stock judgement: analyst views / sell-side reports / long-form opinion stream, with research_entity_id attribution. Prefer this over `news` when forming an investment opinion.
|
|
6342
|
+
description: "PRIMARY research source for stock judgement: analyst views / sell-side reports / long-form opinion stream, with research_entity_id attribution. Prefer this over `news` when forming an investment opinion. Returns `fields=compact` by default (ai_summary + first ~300 chars of content, `content_truncated` flag) — typically 20-50x smaller than full; pass fields='full' only when summaries are not enough. Recommended reading path: `digest` for a one-shot overview → this verb (compact) to scan → `report` for the full text of a single item (`full_text_available=true` means a parsed research report). AH dual-listing: for an A+H listed company pass the A-share canonical to get the consolidated coverage (most domestic analyst views attribute to the A-share security); use HK code only if the user explicitly asks for the HK perspective.",
|
|
6217
6343
|
inputSchema: {
|
|
6218
|
-
code:
|
|
6219
|
-
analyst:
|
|
6220
|
-
institution:
|
|
6221
|
-
since_days:
|
|
6222
|
-
from:
|
|
6223
|
-
to:
|
|
6224
|
-
offset:
|
|
6225
|
-
limit:
|
|
6344
|
+
code: z17.string().regex(/^((SSE|SZSE|BSE):[0-9]{6}|HK:[0-9]{5}|US:[A-Z][A-Z0-9.\-]{0,5})$/).optional().describe("Filter by security canonical_code (e.g. SSE:600519, HK:00700, US:AAPL)"),
|
|
6345
|
+
analyst: z17.string().optional().describe("Analyst Chinese name (exact / fuzzy)"),
|
|
6346
|
+
institution: z17.string().optional().describe("Broker / institution Chinese name"),
|
|
6347
|
+
since_days: z17.number().int().min(1).max(365).default(7).describe("Lookback in days. ≤30 = rolling feed; >30 auto-switches to range history " + "(needs a code/analyst/institution filter; Pro-only up to 365). For an explicit window use from/to."),
|
|
6348
|
+
from: z17.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe("History range start (China date YYYY-MM-DD). Range mode: needs a filter; Pro-only up to 365 days back."),
|
|
6349
|
+
to: z17.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe("History range end (inclusive, China date; defaults to today). Use with from."),
|
|
6350
|
+
offset: z17.number().int().min(0).optional().describe("Pagination offset for paging through long history ranges."),
|
|
6351
|
+
limit: z17.number().int().min(1).max(100).default(30).describe("Max items per page"),
|
|
6352
|
+
fields: z17.enum(["compact", "full"]).optional().describe("Response shape: compact (default — ai_summary + first ~300 chars) or full (complete content)")
|
|
6226
6353
|
},
|
|
6227
6354
|
handler: async (args, ctx) => {
|
|
6228
6355
|
const op = OPERATIONS["views.recent"];
|
|
@@ -6246,6 +6373,8 @@ function buildViewsCallArgs(args) {
|
|
|
6246
6373
|
callArgs.institution = args.institution;
|
|
6247
6374
|
if (typeof args.offset === "number")
|
|
6248
6375
|
callArgs.offset = args.offset;
|
|
6376
|
+
if (args.fields === "compact" || args.fields === "full")
|
|
6377
|
+
callArgs.fields = args.fields;
|
|
6249
6378
|
const explicitRange = typeof args.from === "string" && args.from.length > 0;
|
|
6250
6379
|
if (explicitRange || sinceDays > 30) {
|
|
6251
6380
|
if (!hasFilter) {
|
|
@@ -6267,10 +6396,10 @@ var reportSpec = {
|
|
|
6267
6396
|
name: "report",
|
|
6268
6397
|
description: "Fetch the FULL research-report text behind a view (mineru-parsed long-form), for when the `views` summary is not enough. Only works on views where `full_text_available=true` (gdrive sell-side reports). Two-step usage: default `format=outline` returns a few-KB heading map + total_chars + each heading's char_offset; then call `format=full` with `offset` (e.g. an outline char_offset) to read the body in pages — follow `next_offset` to page through large docs instead of pulling everything at once.",
|
|
6269
6398
|
inputSchema: {
|
|
6270
|
-
view_id:
|
|
6271
|
-
format:
|
|
6272
|
-
offset:
|
|
6273
|
-
max_chars:
|
|
6399
|
+
view_id: z17.string().regex(/^[0-9]+$/).describe("View id from `views` items[].id (must have full_text_available=true)"),
|
|
6400
|
+
format: z17.enum(["outline", "full"]).default("outline").describe("outline=heading map (default); full=body slice"),
|
|
6401
|
+
offset: z17.number().int().min(0).default(0).describe("full mode: start char offset (use an outline char_offset)"),
|
|
6402
|
+
max_chars: z17.number().int().min(1).max(80000).default(40000).describe("full mode: max chars per page (hard cap 80000)")
|
|
6274
6403
|
},
|
|
6275
6404
|
handler: async (args, ctx) => {
|
|
6276
6405
|
const op = OPERATIONS["views.document"];
|
|
@@ -6308,6 +6437,10 @@ function buildViewsCommand() {
|
|
|
6308
6437
|
cmd.addOption(new Option17("--to <date>", "History range end YYYY-MM-DD (inclusive; default today)"));
|
|
6309
6438
|
cmd.addOption(new Option17("--offset <n>", "Pagination offset for long history").default("0"));
|
|
6310
6439
|
cmd.addOption(new Option17("--limit <n>", "Max items (1-100)").default("30"));
|
|
6440
|
+
cmd.addOption(new Option17("--fields <mode>", "Response shape: compact (default) or full").choices([
|
|
6441
|
+
"compact",
|
|
6442
|
+
"full"
|
|
6443
|
+
]));
|
|
6311
6444
|
cmd.action(async (opts) => {
|
|
6312
6445
|
if (!OPERATIONS["views.recent"]) {
|
|
6313
6446
|
emitVerbError("internal_error", "views.recent missing from codegen", undefined, 2);
|
|
@@ -6327,6 +6460,8 @@ function buildViewsCommand() {
|
|
|
6327
6460
|
args.from = opts.from;
|
|
6328
6461
|
if (opts.to)
|
|
6329
6462
|
args.to = opts.to;
|
|
6463
|
+
if (opts.fields)
|
|
6464
|
+
args.fields = opts.fields;
|
|
6330
6465
|
await executeVerb(async (ctx) => viewsSpec.handler(args, ctx));
|
|
6331
6466
|
});
|
|
6332
6467
|
return cmd;
|
|
@@ -6360,6 +6495,7 @@ var ALL_VERB_SPECS = [
|
|
|
6360
6495
|
quoteSpec,
|
|
6361
6496
|
marketStatusSpec,
|
|
6362
6497
|
marketMoversSpec,
|
|
6498
|
+
indexSnapshotSpec,
|
|
6363
6499
|
viewsSpec,
|
|
6364
6500
|
reportSpec,
|
|
6365
6501
|
newsSpec,
|
|
@@ -6394,7 +6530,8 @@ var ALL_VERB_SPECS = [
|
|
|
6394
6530
|
financialsReportsSpec,
|
|
6395
6531
|
financialsSeriesSpec,
|
|
6396
6532
|
ownershipShowSpec,
|
|
6397
|
-
ownershipLockupsSpec
|
|
6533
|
+
ownershipLockupsSpec,
|
|
6534
|
+
capabilitiesSpec
|
|
6398
6535
|
];
|
|
6399
6536
|
|
|
6400
6537
|
// src/tools/mcp.ts
|
|
@@ -7181,7 +7318,7 @@ function buildDoctorCommand() {
|
|
|
7181
7318
|
|
|
7182
7319
|
// src/tools/schema.ts
|
|
7183
7320
|
import { Command as Command27 } from "commander";
|
|
7184
|
-
import { z as
|
|
7321
|
+
import { z as z18 } from "zod";
|
|
7185
7322
|
|
|
7186
7323
|
// src/_generated/help.ts
|
|
7187
7324
|
var HELP = {
|
|
@@ -7245,6 +7382,11 @@ var HELP = {
|
|
|
7245
7382
|
description: "Returns minute-level OHLC bars for multiple A-share securities in one call: up to 20 codes and up to a 7 calendar-day (~5 trading-day) range. Responses use a partial-success envelope: codes the token may not access are reported in `errors[]`, the rest in `items[]` with a flat `bars[]` array where each bar carries its own `trade_date` for client-side grouping. Requires the `bars:30d` or `bars:full` scope.",
|
|
7246
7383
|
example: "echopai bars minute-batch --codes ['SSE:600519', 'SZSE:000001']"
|
|
7247
7384
|
},
|
|
7385
|
+
"capabilities.show": {
|
|
7386
|
+
summary: "Capability changelog and API version discovery.",
|
|
7387
|
+
description: "Returns the current API spec version plus a machine-readable changelog of capability changes (new endpoints, new fields, behavior fixes), newest first. Check it at session start — or after an unexpected response shape — to discover capabilities added since your integration was written. Free and unauthenticated.",
|
|
7388
|
+
example: "echopai capabilities show"
|
|
7389
|
+
},
|
|
7248
7390
|
"concepts.alerts": {
|
|
7249
7391
|
summary: "List currently active concept alerts.",
|
|
7250
7392
|
description: "Returns the live set of concept alerts. Two rules fire: `big_move` when absolute percent change exceeds 3%, and `limit_up_cluster` when a concept has at least 3 limit-up members across at least 5 member stocks.",
|
|
@@ -7357,7 +7499,7 @@ var HELP = {
|
|
|
7357
7499
|
},
|
|
7358
7500
|
"news.feed": {
|
|
7359
7501
|
summary: "List recent news.",
|
|
7360
|
-
description: "Returns recent news. Equivalent to `/v1/news/list`; retained for backward compatibility.",
|
|
7502
|
+
description: "Returns recent news. Equivalent to `/v1/news/list`; retained for backward compatibility. Partner/agent callers receive `fields=compact` by default (id, title, ai_summary, tagged securities, first ~300 chars of content); pass `fields=full` for complete content.",
|
|
7361
7503
|
example: "echopai news feed"
|
|
7362
7504
|
},
|
|
7363
7505
|
"news.get": {
|
|
@@ -7387,12 +7529,12 @@ var HELP = {
|
|
|
7387
7529
|
},
|
|
7388
7530
|
quote: {
|
|
7389
7531
|
summary: "Get real-time quotes for one or more securities.",
|
|
7390
|
-
description: "Returns real-time quotes for one or more A-share securities (canonical codes, e.g. `SSE:600519`): last price, volume, percent change, and bid/ask. Up to 200 codes per call. Requires a `quote:l1`, `quote:l2`, or `quote:delayed` scope.",
|
|
7532
|
+
description: "Returns real-time quotes for one or more A-share securities (canonical codes, e.g. `SSE:600519`): last price, volume, percent change, and bid/ask. Up to 200 codes per call. The response carries a `session` label (`pre_open` / `auction` / `open` / `break` / `closed`) and, outside continuous trading, an explanatory `note`: during 9:00–9:14 pre-open the previous session's snapshot is returned; during the 9:15–9:29 call auction, prices are indicative auction match prices. Rows whose feed has stopped updating (suspension / feed drop) keep their last snapshot and are flagged `stale: true` with `stale_since`. Requires a `quote:l1`, `quote:l2`, or `quote:delayed` scope.",
|
|
7391
7533
|
example: "echopai quote --codes ['SSE:600519', 'SZSE:000001']"
|
|
7392
7534
|
},
|
|
7393
7535
|
"quote.scan": {
|
|
7394
7536
|
summary: "Snapshot every A-share real-time quote in one call.",
|
|
7395
|
-
description: "Returns a real-time quote for every A-share in a single call — use it for full-market scans or to discover a universe of interest when you do not yet know which codes to query. Filter with `exchange=SSE|SZSE|BSE` to narrow to one exchange. The payload is large (~3 MB, ~5,800 instruments), so pair it with `--fields`, `--jq`, or `--max-bytes` to trim it.
|
|
7537
|
+
description: "Returns a real-time quote for every A-share in a single call — use it for full-market scans or to discover a universe of interest when you do not yet know which codes to query. Filter with `exchange=SSE|SZSE|BSE` to narrow to one exchange. The payload is large (~3 MB, ~5,800 instruments), so pair it with `--fields`, `--jq`, or `--max-bytes` to trim it. The response carries a `session` label (`pre_open` / `auction` / `open` / `break` / `closed`) plus an explanatory `note` outside continuous trading: during 9:00–9:14 pre-open the previous session's snapshot is returned; during the 9:15–9:29 call auction, prices are indicative auction match prices. Instruments whose feed has stopped updating (suspension / feed drop) are excluded from the default scan; pass `include=all` to keep them, flagged with `stale: true` and `stale_since`. Each item also includes `main_net_in` (current-day cumulative net main-capital inflow in CNY, which may be negative) and a companion `main_net_in_stale` flag (true when served from the last-close fallback). Requires a `quote:l1`, `quote:l2`, or `quote:delayed` scope.",
|
|
7396
7538
|
example: "echopai quote scan"
|
|
7397
7539
|
},
|
|
7398
7540
|
"search.semantic": {
|
|
@@ -7442,7 +7584,7 @@ var HELP = {
|
|
|
7442
7584
|
},
|
|
7443
7585
|
"views.feed": {
|
|
7444
7586
|
summary: "List analyst views.",
|
|
7445
|
-
description: "Returns a stream of analyst views, sell-side research, and long-form opinion. Filter by institution, analyst, security, or recency (`hours`). Requires the `views:read` scope.",
|
|
7587
|
+
description: "Returns a stream of analyst views, sell-side research, and long-form opinion. Filter by institution, analyst, security, or recency (`hours`). Partner/agent callers receive `fields=compact` by default (id, ai_summary, attribution, tagged securities, first ~300 chars of content); pass `fields=full` for complete content. Requires the `views:read` scope.",
|
|
7446
7588
|
example: "echopai views feed"
|
|
7447
7589
|
},
|
|
7448
7590
|
"views.get": {
|
|
@@ -7461,7 +7603,7 @@ var HELP = {
|
|
|
7461
7603
|
function verbToRecord(spec) {
|
|
7462
7604
|
let inputSchema;
|
|
7463
7605
|
try {
|
|
7464
|
-
inputSchema =
|
|
7606
|
+
inputSchema = z18.toJSONSchema(z18.object(spec.inputSchema));
|
|
7465
7607
|
} catch {
|
|
7466
7608
|
inputSchema = {
|
|
7467
7609
|
type: "object",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "echopai",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Command-line interface for the EchoPai Open Platform: stock-market data, news, analyst views, sentiment, signals, backtests.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://echopai.com",
|