File size: 8,123 Bytes
cf05d66
 
 
 
 
 
 
4567005
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf05d66
 
 
4567005
cf05d66
4567005
 
 
 
cf05d66
4567005
cf05d66
 
 
4567005
 
 
cf05d66
4567005
cf05d66
4567005
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf05d66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4567005
 
 
 
cf05d66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4567005
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
To use this application (igardner/StockAnalysis: Structured stock analysis as JSON for agents):
API schema: GET https://igardner-stockanalysis.hf.space/gradio_api/info
Call endpoint: POST https://igardner-stockanalysis.hf.space/gradio_api/call/v2/analyze {"ticker": "AAPL", "horizon": "3 months", "risk_profile": "balanced", "question": ""}
Poll result: GET https://igardner-stockanalysis.hf.space/gradio_api/call/analyze/{event_id}
File inputs: none - all inputs are JSON scalars.
Auth: Bearer $HF_TOKEN (https://huggingface.co/settings/tokens)

# StockAnalysis agent contract

This file is the concrete contract for agents. The Hub also generates a live
`agents.md` at `https://huggingface.co/spaces/igardner/StockAnalysis/agents.md`.
Always fetch `/gradio_api/info` before calling. The live schema is the runtime
contract; this file explains the boundaries and the expected response shapes.

## What this Space does

- Accepts a ticker, horizon, risk profile, and optional question.
- Sends that request to a separate stock-analysis project.
- Returns three outputs in order: JSON, the raw upstream body, and a short
  human-readable status string.
- If the upstream returns text and a local parser is configured, converts that
  text to JSON without inventing prices, targets, or recommendations.

The Analyze request is read-only. It does not place trades, move funds, or
connect to a brokerage account.

## Boundaries: what this Space will not do

- It is not financial advice and is not a substitute for a licensed advisor.
- It does not guarantee returns, accuracy, completeness, availability, or
  latency. Do not represent it as promising 10x gains or any other return.
- It does not execute trades or manage money.
- It does not verify the external project's claims or data.
- It does not provide personalized advice. Treat output as research material
  that a human reviews.
- It does not accept file inputs. Do not call `/gradio_api/upload`.
- It does not expose the smoke test as part of the agent contract. The smoke
  test events are marked private; do not call them.
- It does not promise uptime. This is a CPU-basic Space and can sleep, restart,
  or be rebuilt.
- It does not intentionally persist Analyze requests. The external project may
  have its own retention policy.

## Promises: what agents can rely on

- When the Gradio call completes, it returns exactly three outputs in this
  order: JSON result, raw upstream body, status string.
- The first output is JSON-serializable. Error and configuration failures are
  returned as JSON objects instead of a successful-looking analysis.
- Expected failures use these `status` values: `not_configured`,
  `invalid_input`, or `error`. A text-to-JSON wrapper uses `status: "ok"` plus
  `source: "external+local_parser"`.
- An upstream JSON response is passed through unchanged. Its shape is defined by
  the external project, not by this Space.
- Missing or empty tickers return `invalid_input`. Unknown horizon or risk
  values are coerced to `3 months` and `balanced`.
- The Space never returns `HF_TOKEN` or any server secret in its outputs.
- Private smoke-test outputs are not part of the Analyze response.

## Inputs

| Name | Type | Required | Default | Rules |
|---|---|---|---|---|
| `ticker` | string | yes | none | Uppercased and trimmed. Maximum 24 characters. Empty is rejected. |
| `horizon` | string | no | `3 months` | `1 week`, `1 month`, `3 months`, `6 months`, or `1 year`. Unknown values become `3 months`. |
| `risk_profile` | string | no | `balanced` | `conservative`, `balanced`, or `aggressive`. Unknown values become `balanced`. |
| `question` | string | no | empty | Optional. Truncated to 2000 characters. Do not put secrets or personal data here. |

There are no file inputs.

## Outputs

1. JSON result. Read this first.
2. Raw upstream response as text. May be empty.
3. Human-readable status string. Do not parse this as machine data.

The JSON result can be one of these shapes:

- Upstream JSON, passed through unchanged.
- `{"status": "ok", "ticker": "...", "http_status": 200, "content_type": "...", "raw": "..."}`
  when the upstream returned text and no parser was configured.
- `{"status": "ok", "ticker": "...", "source": "external+local_parser", "parser": {"model": "..."}, "analysis": <JSON>, "raw": "..."}`
  when the local parser succeeded.
- `{"status": "not_configured", "message": "..."}` when `EXTERNAL_API_URL` is
  unset.
- `{"status": "invalid_input", "error": "..."}` for bad input.
- `{"status": "error", "http_status": ..., "error": "...", "raw": "..."}` for
  upstream failures.
- The text-wrapper shape plus `parse_error` when the local parser failed.

Check for the `status` field before treating a result as analysis. Our error
envelopes include `ticker` and an `error` or `message` field. Upstream JSON is
not wrapped, so its own fields are whatever the external project returns.

## Call with curl

```bash
EVENT_ID=$(curl -sS -X POST \
  "https://igardner-stockanalysis.hf.space/gradio_api/call/v2/analyze" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $HF_TOKEN" \
  -d '{"ticker":"AAPL","horizon":"3 months","risk_profile":"balanced","question":""}' \
  | python -c 'import json,sys; print(json.load(sys.stdin)["event_id"])')

curl -sS -N \
  "https://igardner-stockanalysis.hf.space/gradio_api/call/analyze/$EVENT_ID" \
  -H "Authorization: Bearer $HF_TOKEN"
```

The POST returns `{"event_id": "..."}`. The GET streams Server-Sent Events. The
final event is `complete` and its `data` field is the three-element output list.
An `error` event means the call failed; a stream that ends without `complete`
should be treated as a failure.

If a client only supports the older call shape, send the same inputs as a
positional list to `/gradio_api/call/analyze`:

```json
{"data": ["AAPL", "3 months", "balanced", ""]}
```

## Call with the Python client

```python
import os
from gradio_client import Client

client = Client("igardner/StockAnalysis", token=os.environ["HF_TOKEN"])
result = client.predict(
    "AAPL",
    "3 months",
    "balanced",
    "",
    api_name="/analyze",
)
print(result)
```

## Error handling and retries

- Check the JSON result's `status` before using any analysis fields.
- Do not retry `invalid_input` or `not_configured`. Fix the input or ask the
  Space owner to set `EXTERNAL_API_URL`.
- For HTTP 429, 5xx, network errors, or a stream without `complete`, retry with
  exponential backoff and a small retry cap (for example, three attempts).
  Honor `Retry-After` when it is present.
- Do not retry a `parse_error` blindly. The raw upstream body is still in the
  second output, so use that if your client can parse it.
- The server allows up to four concurrent Analyze events. Stay below that, and
  do not flood the Space with parallel requests.

## Auth and data handling

- Send `Authorization: Bearer $HF_TOKEN` on both the POST and the poll GET.
- Never put the token in the JSON body, the `question` field, or a URL query
  string.
- `HF_TOKEN` is for Space authentication and rate limits. The Space's own
  outbound token is a Space secret and is never returned to clients.
- The ticker and question are sent to the external project. Do not send
  secrets, credentials, or personal data.
- The Space does not intentionally store Analyze requests. The external project
  may log or retain them under its own policy.

## Discovery and versioning

- Fetch `GET /gradio_api/info` at the start of a session. Do not hardcode
  parameter names, return counts, or endpoint paths beyond the documented
  fallback.
- The live `/agents.md` route is generated by Hugging Face from Space metadata.
  This repository copy is documentation, not a replacement for the live schema.
- The external project and the custom model can change independently. The custom
  model is configured with `STOCK_MODEL_ID` and is currently blank.

## Disclaimer

This is research tooling, not financial advice. Output may be incomplete or
wrong. No return is guaranteed, and you can lose money. Nothing in this contract
promises a specific gain, including 10x.